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

#include "paddle/fluid/operators/roll_op.h"

#include <memory>
#include <vector>

namespace paddle {
namespace operators {

using framework::Tensor;

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

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

    auto dims = ctx->Attrs().Get<std::vector<int64_t>>("axis");
    auto shifts = ctx->Attrs().Get<std::vector<int64_t>>("shifts");

    PADDLE_ENFORCE_EQ(dims.size(), shifts.size(),
                      platform::errors::InvalidArgument(
                          "Attr(dims).size() should be equl to "
                          "Attr(shifts).size(). But received "
                          "Attr(dims).size() = %d, Attr(shifts).size() = %d",
                          dims.size(), shifts.size()));

    ctx->SetOutputDim("Out", ctx->GetInputDim("X"));
    auto type = ctx->GetInputsVarType("X")[0];
    if (type == framework::proto::VarType::LOD_TENSOR) {
      ctx->ShareLoD("X", /*->*/ "Out");
    }
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    auto data_type = OperatorWithKernel::IndicateVarDataType(ctx, "X");
    return framework::OpKernelType(data_type, ctx.device_context());
  }
};

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

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE_EQ(ctx->HasInput(framework::GradVarName("Out")), true,
                      platform::errors::InvalidArgument(
                          "Input(Out@GRAD) should be not null."));
    PADDLE_ENFORCE_EQ(ctx->HasOutput(framework::GradVarName("X")), true,
                      platform::errors::InvalidArgument(
                          "Output(X@GRAD) should be not null."));

    ctx->SetOutputDim(framework::GradVarName("X"), ctx->GetInputDim("X"));
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    return framework::OpKernelType(OperatorWithKernel::IndicateVarDataType(
                                       ctx, framework::GradVarName("Out")),
                                   ctx.device_context());
  }
};

class RollOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X", "(Tensor) the input tensor.");
    AddOutput("Out", "(Tensor), the output tensor.");
    AddAttr<std::vector<int64_t>>("shifts",
                                  "The number of places by which the elements "
                                  "of the tensor are shifted.")
        .SetDefault({});
    AddAttr<std::vector<int64_t>>(
        "axis",
        "Axis along which to roll. It must have the same size "
        "with shifts.")
        .SetDefault({});
    AddComment(R"DOC(
    Roll the tensor along the given dimension(s).
    Elements that are shifted beyond the last position
    are re-introduced at the first position. If a dimension
    is not specified, the tensor will be flattened before
    rolling and then restored to the original shape.
    )DOC");
  }
};

template <typename T>
class RollGradMaker : public framework::SingleGradOpMaker<T> {
 public:
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;

 protected:
  void Apply(GradOpPtr<T> op) const override {
    op->SetType("roll_grad");
    op->SetInput("X", this->Input("X"));
    op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
    op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
    op->SetAttrMap(this->Attrs());
  }
};

DECLARE_NO_NEED_BUFFER_VARS_INFERER(RollGradNoNeedBufferVarsInferer, "X");
}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(roll, ops::RollOp, ops::RollOpMaker,
                  ops::RollGradMaker<paddle::framework::OpDesc>,
                  ops::RollGradMaker<paddle::imperative::OpBase>);
REGISTER_OPERATOR(roll_grad, ops::RollGradOp,
                  ops::RollGradNoNeedBufferVarsInferer);
REGISTER_OP_CPU_KERNEL(
    roll, ops::RollKernel<paddle::platform::CPUDeviceContext, float>,
    ops::RollKernel<paddle::platform::CPUDeviceContext, double>,
    ops::RollKernel<paddle::platform::CPUDeviceContext, int>,
    ops::RollKernel<paddle::platform::CPUDeviceContext, int64_t>);
REGISTER_OP_CPU_KERNEL(
    roll_grad, ops::RollGradKernel<paddle::platform::CPUDeviceContext, float>,
    ops::RollGradKernel<paddle::platform::CPUDeviceContext, double>,
    ops::RollGradKernel<paddle::platform::CPUDeviceContext, int>,
    ops::RollGradKernel<paddle::platform::CPUDeviceContext, int64_t>);
<commit_msg>test=develop, add op_register_version for roll_op (#30023)<commit_after>// Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "paddle/fluid/operators/roll_op.h"
#include <memory>
#include <vector>
#include "paddle/fluid/framework/op_version_registry.h"

namespace paddle {
namespace operators {

using framework::Tensor;

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

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

    auto dims = ctx->Attrs().Get<std::vector<int64_t>>("axis");
    auto shifts = ctx->Attrs().Get<std::vector<int64_t>>("shifts");

    PADDLE_ENFORCE_EQ(dims.size(), shifts.size(),
                      platform::errors::InvalidArgument(
                          "Attr(dims).size() should be equl to "
                          "Attr(shifts).size(). But received "
                          "Attr(dims).size() = %d, Attr(shifts).size() = %d",
                          dims.size(), shifts.size()));

    ctx->SetOutputDim("Out", ctx->GetInputDim("X"));
    auto type = ctx->GetInputsVarType("X")[0];
    if (type == framework::proto::VarType::LOD_TENSOR) {
      ctx->ShareLoD("X", /*->*/ "Out");
    }
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    auto data_type = OperatorWithKernel::IndicateVarDataType(ctx, "X");
    return framework::OpKernelType(data_type, ctx.device_context());
  }
};

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

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE_EQ(ctx->HasInput(framework::GradVarName("Out")), true,
                      platform::errors::InvalidArgument(
                          "Input(Out@GRAD) should be not null."));
    PADDLE_ENFORCE_EQ(ctx->HasOutput(framework::GradVarName("X")), true,
                      platform::errors::InvalidArgument(
                          "Output(X@GRAD) should be not null."));

    ctx->SetOutputDim(framework::GradVarName("X"), ctx->GetInputDim("X"));
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    return framework::OpKernelType(OperatorWithKernel::IndicateVarDataType(
                                       ctx, framework::GradVarName("Out")),
                                   ctx.device_context());
  }
};

class RollOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X", "(Tensor) the input tensor.");
    AddOutput("Out", "(Tensor), the output tensor.");
    AddAttr<std::vector<int64_t>>("shifts",
                                  "The number of places by which the elements "
                                  "of the tensor are shifted.")
        .SetDefault({});
    AddAttr<std::vector<int64_t>>(
        "axis",
        "Axis along which to roll. It must have the same size "
        "with shifts.")
        .SetDefault({});
    AddComment(R"DOC(
    Roll the tensor along the given dimension(s).
    Elements that are shifted beyond the last position
    are re-introduced at the first position. If a dimension
    is not specified, the tensor will be flattened before
    rolling and then restored to the original shape.
    )DOC");
  }
};

template <typename T>
class RollGradMaker : public framework::SingleGradOpMaker<T> {
 public:
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;

 protected:
  void Apply(GradOpPtr<T> op) const override {
    op->SetType("roll_grad");
    op->SetInput("X", this->Input("X"));
    op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
    op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
    op->SetAttrMap(this->Attrs());
  }
};

DECLARE_NO_NEED_BUFFER_VARS_INFERER(RollGradNoNeedBufferVarsInferer, "X");
}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(roll, ops::RollOp, ops::RollOpMaker,
                  ops::RollGradMaker<paddle::framework::OpDesc>,
                  ops::RollGradMaker<paddle::imperative::OpBase>);
REGISTER_OPERATOR(roll_grad, ops::RollGradOp,
                  ops::RollGradNoNeedBufferVarsInferer);
REGISTER_OP_CPU_KERNEL(
    roll, ops::RollKernel<paddle::platform::CPUDeviceContext, float>,
    ops::RollKernel<paddle::platform::CPUDeviceContext, double>,
    ops::RollKernel<paddle::platform::CPUDeviceContext, int>,
    ops::RollKernel<paddle::platform::CPUDeviceContext, int64_t>);
REGISTER_OP_CPU_KERNEL(
    roll_grad, ops::RollGradKernel<paddle::platform::CPUDeviceContext, float>,
    ops::RollGradKernel<paddle::platform::CPUDeviceContext, double>,
    ops::RollGradKernel<paddle::platform::CPUDeviceContext, int>,
    ops::RollGradKernel<paddle::platform::CPUDeviceContext, int64_t>);

REGISTER_OP_VERSION(roll)
    .AddCheckpoint(
        R"ROC(
      Upgrade roll add 1 attribute [axis], delete 1 attribute[dims].
    )ROC",
        paddle::framework::compatible::OpVersionDesc()
            .NewAttr("axis",
                     "(std::vector<int64_t>) Axis along which to roll. "
                     "It must have the same size with shifts.",
                     std::vector<int64_t>())
            .DeleteAttr("dims",
                        "(std::vector<int64_t>) Dims along which to roll. "
                        "It must have the same size with shifts."));
<|endoftext|>


<commit_before>#include <stdio.h>
#include <cstdint>
#include <iostream>
#include <gtest/gtest.h>
#include <glog/logging.h>

#include <tudocomp/util.hpp>

#include <tudocomp_driver/Registry.hpp>
#include <tudocomp/AlgorithmStringParser.hpp>

#include "test/util.hpp"
#include "test/driver_util.hpp"

TEST(TudocompDriver, list) {
    // Test that we got at some output with --list

    auto list = driver_test::driver("--list");

    std::cout << list;

    // Check that the output is long enough to not be empty
    ASSERT_GE(list.size(), 100u);

}

TEST(TudocompDriver, algorithm_header) {
    std::string text = "asdfghjklöä";
    bool abort = false;
    // Without header
    driver_test::roundtrip("lz78(ascii)", "_header_test_0", text, true, abort, true).check();

    // With header
    driver_test::roundtrip("lz78(ascii)", "_header_test_1", text, false, abort, true).check();

    ASSERT_FALSE(abort);

    std::string text0 = test::read_test_file(driver_test::roundtrip_comp_file_name(
        "lz78(ascii)", "_header_test_0"));

    ASSERT_FALSE(text0.find("lz78(ascii)%") == 0);

    std::string text1 = test::read_test_file(driver_test::roundtrip_comp_file_name(
        "lz78(ascii)", "_header_test_1"));

    ASSERT_TRUE(text1.find("lz78(ascii)%") == 0);

}

TEST(Registry, smoketest) {
    using namespace tdc_algorithms;
    using ast::Value;
    using ast::Arg;
    ast::Parser p { "foo(abc, def=ghi, x = z, "
                    "jkl=mno(p, q=\"1\"), q)" };

    Value a = p.parse_value();

    ASSERT_TRUE(a.is_invokation());
    ASSERT_EQ(a.invokation_name(), "foo");
    auto& b = a.invokation_arguments();
    ASSERT_EQ(b.size(), 5);

        ASSERT_FALSE(b[0].has_keyword());
        ASSERT_FALSE(b[0].has_type());
        ASSERT_EQ(b[0].value().invokation_name(), "abc");

        ASSERT_TRUE(b[1].has_keyword());
        ASSERT_FALSE(b[1].has_type());
        ASSERT_EQ(b[1].keyword(), "def");
        ASSERT_EQ(b[1].value().invokation_name(), "ghi");

        ASSERT_TRUE(b[2].has_keyword());
        ASSERT_EQ(b[2].keyword(), "x");
        ASSERT_EQ(b[2].value().invokation_name(), "z");

        ASSERT_TRUE(b[3].has_keyword());
        ASSERT_FALSE(b[3].has_type());
        ASSERT_FALSE(b[3].type_is_static());
        ASSERT_EQ(b[3].keyword(), "jkl");
        ASSERT_EQ(b[3].value().invokation_name(), "mno");

        auto& c = b[3].value().invokation_arguments();
        ASSERT_EQ(c.size(), 2);

            ASSERT_FALSE(c[1].value().is_invokation());
            ASSERT_EQ(c[1].value().string_value(), "1");

        ASSERT_FALSE(b[4].has_keyword());
        ASSERT_EQ(b[4].value().invokation_name(), "q");
}

TEST(Registry, decl) {
    using namespace tdc_algorithms;
    decl::Algorithm b {
        "foo",
        {
            decl::Arg("a", false, "b"),
            decl::Arg("c", false, "d", ast::Value("e", {})),
            decl::Arg("f", true, "g"),
        },
        "blub",
        true,
    };

    ASSERT_EQ(b.name(), "foo");
    ASSERT_EQ(b.arguments().size(), 3);

    ASSERT_EQ(b.arguments()[0].name(), "a");
    ASSERT_EQ(b.arguments()[0].type(), "b");
    ASSERT_FALSE(b.arguments()[0].is_static());

    ASSERT_EQ(b.arguments()[1].name(), "c");
    ASSERT_EQ(b.arguments()[1].type(), "d");
    ASSERT_TRUE(b.arguments()[1].has_default());
    ASSERT_EQ(b.arguments()[1].default_value().invokation_name(), "e");
    ASSERT_FALSE(b.arguments()[1].is_static());

    ASSERT_EQ(b.arguments()[2].name(), "f");
    ASSERT_EQ(b.arguments()[2].type(), "g");
    ASSERT_TRUE(b.arguments()[2].is_static());
    ASSERT_EQ(b.doc(), "blub");
    ASSERT_EQ(b.add_null_terminator(), true);

}

TEST(Registry, lookup) {
    using namespace tdc_algorithms;
    Registry& r = REGISTRY;
    auto av = r.parse_algorithm_id("lz78(dict_size = \"100\")");
    auto c = r.select_compressor_or_exit(av);
    auto av2 = r.parse_algorithm_id("fib(n = \"10\")", "generator");
    auto g = r.select_generator_or_exit(av2);
}

TEST(Registry, dynamic_options) {
    using namespace tdc_algorithms;

    Registry& r = REGISTRY;

    struct MySub {
        inline static Meta meta() {
            Meta y("b", "x");
            y.option("l").dynamic("zzz");
            return y;
        }
    };
    struct MyCompressor: public Compressor {
        inline static Meta meta() {
            Meta y("compressor", "foo");
            y.option("a").templated<MySub>();
            y.option("c").dynamic();
            y.option("d").dynamic("asdf");
            return y;
        }

        using Compressor::Compressor;
        inline virtual void decompress(Input& input, Output& output) {}

        inline virtual void compress(Input& input, Output& output) {
            auto s = output.as_stream();
            auto t = input.as_view();

            ASSERT_EQ(t, "test");
            s << "check";

            ASSERT_TRUE((env().option("a"), true));
            ASSERT_TRUE((env().option("c"), true));
            ASSERT_TRUE((env().option("d"), true));

            ASSERT_EQ(env().option("c").as_string(), "qwerty");
            ASSERT_EQ(env().option("d").as_string(), "asdf");

            auto& a = env().option("a").as_algorithm();
            auto& a_options = a.arguments();
            ASSERT_EQ(a.name(), "x");
            ASSERT_EQ(a_options.at("l").as_string(), "zzz");
        }
    };

    r.register_compressor<MyCompressor>();

    auto av = r.parse_algorithm_id("foo(x, \"qwerty\")");
    auto c = r.select_compressor_or_exit(av);
    std::vector<uint8_t> data;
    Output out(data);
    Input inp("test");
    c->compress(inp, out);

    ASSERT_EQ(View(data), "check");
}

TEST(TudocompDriver, all_compressors_defined) {
    using namespace tdc_algorithms;

    Registry& r = REGISTRY;
    auto s = r.check_for_undefined_compressors();
    bool has_undefined_compressors = s.size() > 0;
    if (has_undefined_compressors) {
        std::stringstream ss;
        for (auto& s2 : s) {
            ss << "Undefined compressor: " << s2 << "\n";
        }
        EXPECT_FALSE(has_undefined_compressors) << ss.str();
    }
}

TEST(Registry, chain_sugar) {
    using namespace tdc_algorithms;
    using ast::Value;
    using ast::Arg;
    auto cmp = [](std::string sa, std::string sb) {
        ast::Parser p { sa };
        Value a = p.parse_value();
        ASSERT_EQ(a.to_string(), sb);
    };

    cmp("foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = 3), q)",
        "foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = \"3\"), q)");
    cmp("foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = 3), q):algo2",
        "chain("
            "foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = \"3\"), q)"
            ", algo2)");
    cmp("foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = 3), q):algo2:algo3('asdf')",
        "chain("
            "chain("
                "foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = \"3\"), q)"
                ", algo2)"
        ", algo3(\"asdf\"))");
}
<commit_msg>Fix tudocomp_driver tests<commit_after>#include <stdio.h>
#include <cstdint>
#include <iostream>
#include <gtest/gtest.h>
#include <glog/logging.h>

#include <tudocomp/util.hpp>

#include <tudocomp_driver/Registry.hpp>
#include <tudocomp/AlgorithmStringParser.hpp>

#include "test/util.hpp"
#include "test/driver_util.hpp"

TEST(TudocompDriver, list) {
    // Test that we got at some output with --list

    auto list = driver_test::driver("--list");

    std::cout << list;

    // Check that the output is long enough to not be empty
    ASSERT_GE(list.size(), 100u);

}

TEST(TudocompDriver, algorithm_header) {
    std::string text = "asdfghjklöä";
    bool abort = false;
    // Without header
    driver_test::roundtrip("lz78(ascii)", "_header_test_0", text, true, abort, true).check();

    // With header
    driver_test::roundtrip("lz78(ascii)", "_header_test_1", text, false, abort, true).check();

    ASSERT_FALSE(abort);

    std::string text0 = test::read_test_file(driver_test::roundtrip_comp_file_name(
        "lz78(ascii)", "_header_test_0"));

    ASSERT_FALSE(text0.find("lz78(ascii)%") == 0);

    std::string text1 = test::read_test_file(driver_test::roundtrip_comp_file_name(
        "lz78(ascii)", "_header_test_1"));

    ASSERT_TRUE(text1.find("lz78(ascii)%") == 0);

}

TEST(Registry, smoketest) {
    using namespace tdc_algorithms;
    using ast::Value;
    using ast::Arg;
    ast::Parser p { "foo(abc, def=ghi, x = z, "
                    "jkl=mno(p, q=\"1\"), q)" };

    Value a = p.parse_value();

    ASSERT_TRUE(a.is_invokation());
    ASSERT_EQ(a.invokation_name(), "foo");
    auto& b = a.invokation_arguments();
    ASSERT_EQ(b.size(), 5);

        ASSERT_FALSE(b[0].has_keyword());
        ASSERT_FALSE(b[0].has_type());
        ASSERT_EQ(b[0].value().invokation_name(), "abc");

        ASSERT_TRUE(b[1].has_keyword());
        ASSERT_FALSE(b[1].has_type());
        ASSERT_EQ(b[1].keyword(), "def");
        ASSERT_EQ(b[1].value().invokation_name(), "ghi");

        ASSERT_TRUE(b[2].has_keyword());
        ASSERT_EQ(b[2].keyword(), "x");
        ASSERT_EQ(b[2].value().invokation_name(), "z");

        ASSERT_TRUE(b[3].has_keyword());
        ASSERT_FALSE(b[3].has_type());
        ASSERT_FALSE(b[3].type_is_static());
        ASSERT_EQ(b[3].keyword(), "jkl");
        ASSERT_EQ(b[3].value().invokation_name(), "mno");

        auto& c = b[3].value().invokation_arguments();
        ASSERT_EQ(c.size(), 2);

            ASSERT_FALSE(c[1].value().is_invokation());
            ASSERT_EQ(c[1].value().string_value(), "1");

        ASSERT_FALSE(b[4].has_keyword());
        ASSERT_EQ(b[4].value().invokation_name(), "q");
}

TEST(Registry, decl) {
    using namespace tdc_algorithms;
    decl::Algorithm b {
        "foo",
        {
            decl::Arg("a", false, "b"),
            decl::Arg("c", false, "d", ast::Value("e", {})),
            decl::Arg("f", true, "g"),
        },
        "blub",
        tdc::ds::InputRestrictionsAndFlags(tdc::io::InputRestrictions({ 0 }, true), tdc::ds::SA),
    };

    ASSERT_EQ(b.name(), "foo");
    ASSERT_EQ(b.arguments().size(), 3);

    ASSERT_EQ(b.arguments()[0].name(), "a");
    ASSERT_EQ(b.arguments()[0].type(), "b");
    ASSERT_FALSE(b.arguments()[0].is_static());

    ASSERT_EQ(b.arguments()[1].name(), "c");
    ASSERT_EQ(b.arguments()[1].type(), "d");
    ASSERT_TRUE(b.arguments()[1].has_default());
    ASSERT_EQ(b.arguments()[1].default_value().invokation_name(), "e");
    ASSERT_FALSE(b.arguments()[1].is_static());

    ASSERT_EQ(b.arguments()[2].name(), "f");
    ASSERT_EQ(b.arguments()[2].type(), "g");
    ASSERT_TRUE(b.arguments()[2].is_static());
    ASSERT_EQ(b.doc(), "blub");
    ASSERT_EQ(b.textds_flags(), tdc::ds::InputRestrictionsAndFlags(tdc::io::InputRestrictions({ 0 }, true), tdc::ds::SA));

}

TEST(Registry, lookup) {
    using namespace tdc_algorithms;
    Registry& r = REGISTRY;
    auto av = r.parse_algorithm_id("lz78(dict_size = \"100\")");
    auto c = r.select_compressor_or_exit(av);
    auto av2 = r.parse_algorithm_id("fib(n = \"10\")", "generator");
    auto g = r.select_generator_or_exit(av2);
}

TEST(Registry, dynamic_options) {
    using namespace tdc_algorithms;

    Registry& r = REGISTRY;

    struct MySub {
        inline static Meta meta() {
            Meta y("b", "x");
            y.option("l").dynamic("zzz");
            return y;
        }
    };
    struct MyCompressor: public Compressor {
        inline static Meta meta() {
            Meta y("compressor", "foo");
            y.option("a").templated<MySub>();
            y.option("c").dynamic();
            y.option("d").dynamic("asdf");
            return y;
        }

        using Compressor::Compressor;
        inline virtual void decompress(Input& input, Output& output) {}

        inline virtual void compress(Input& input, Output& output) {
            auto s = output.as_stream();
            auto t = input.as_view();

            ASSERT_EQ(t, "test");
            s << "check";

            ASSERT_TRUE((env().option("a"), true));
            ASSERT_TRUE((env().option("c"), true));
            ASSERT_TRUE((env().option("d"), true));

            ASSERT_EQ(env().option("c").as_string(), "qwerty");
            ASSERT_EQ(env().option("d").as_string(), "asdf");

            auto& a = env().option("a").as_algorithm();
            auto& a_options = a.arguments();
            ASSERT_EQ(a.name(), "x");
            ASSERT_EQ(a_options.at("l").as_string(), "zzz");
        }
    };

    r.register_compressor<MyCompressor>();

    auto av = r.parse_algorithm_id("foo(x, \"qwerty\")");
    auto c = r.select_compressor_or_exit(av);
    std::vector<uint8_t> data;
    Output out(data);
    Input inp("test");
    c->compress(inp, out);

    ASSERT_EQ(View(data), "check");
}

TEST(TudocompDriver, all_compressors_defined) {
    using namespace tdc_algorithms;

    Registry& r = REGISTRY;
    auto s = r.check_for_undefined_compressors();
    bool has_undefined_compressors = s.size() > 0;
    if (has_undefined_compressors) {
        std::stringstream ss;
        for (auto& s2 : s) {
            ss << "Undefined compressor: " << s2 << "\n";
        }
        EXPECT_FALSE(has_undefined_compressors) << ss.str();
    }
}

TEST(Registry, chain_sugar) {
    using namespace tdc_algorithms;
    using ast::Value;
    using ast::Arg;
    auto cmp = [](std::string sa, std::string sb) {
        ast::Parser p { sa };
        Value a = p.parse_value();
        ASSERT_EQ(a.to_string(), sb);
    };

    cmp("foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = 3), q)",
        "foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = \"3\"), q)");
    cmp("foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = 3), q):algo2",
        "chain("
            "foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = \"3\"), q)"
            ", algo2)");
    cmp("foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = 3), q):algo2:algo3('asdf')",
        "chain("
            "chain("
                "foo(abc, def = ghi, x = z, jkl = mno(p, q = \"1\", x = \"3\"), q)"
                ", algo2)"
        ", algo3(\"asdf\"))");
}
<|endoftext|>


<commit_before>// Filename: httpDate.cxx
// Created by:  drose (28Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "httpDate.h"

#include <ctype.h>

static const int num_weekdays = 7;
static const char * const weekdays[num_weekdays] = {
  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

static const int num_months = 12;
static const char * const months[num_months] = {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::Constructor
//       Access: Published
//  Description: Decodes the string into a sensible date.  Returns 0
//               (!is_valid()) if the string cannot be correctly
//               decoded.
////////////////////////////////////////////////////////////////////
HTTPDate::
HTTPDate(const string &format) {
  _time = (time_t)(-1);

  struct tm t;
  memset(&t, 0, sizeof(t));

  bool got_weekday = false;
  bool got_month = false;
  bool got_day = false;
  bool got_year = false;
  bool got_hour = false;
  bool got_minute = false;
  bool got_second = false;
  bool got_timezone = false;

  enum ExpectNext {
    EN_none,
    EN_second,
    EN_year
  };
  ExpectNext expect_next = EN_none;

  size_t pos = 0;
  string token = get_token(format, pos);
  while (!token.empty()) {
    ExpectNext expected = expect_next;
    expect_next = EN_none;

    if (isdigit(token[0])) {
      // Here's a number.
      int value = atoi(token.c_str());
      if (token[token.length() - 1] == ':') {
        // If it ends in a colon, it must be hh or mm.
        if (!got_hour) {
          t.tm_hour = value;
          got_hour = true;

        } else if (!got_minute) {
          t.tm_min = value;
          got_minute = true;
          expect_next = EN_second;

        } else {
          return;
        }

      } else if (token[token.length() - 1] == '/') {
        // If it ends in a colon, it must be mm/dd/.
        if (!got_month) {
          t.tm_mon = value - 1;
          got_month = true;

        } else if (!got_day) {
          t.tm_mday = value;
          got_day = true;
          expect_next = EN_year;

        } else {
          return;
        }

      } else {
        if (expected == EN_second) {
          // The first number following hh:mm: is always the seconds.
          t.tm_sec = value;
          got_second = true;

        } else if (expected == EN_year) {
          // The first number following mm/dd/ is always the year.
          t.tm_year = value;
          got_year = true;

        } else if (!got_day) {
          // Assume it's a day.
          t.tm_mday = value;
          got_day = true;

        } else if (!got_year) {
          // It must be the year.
          t.tm_year = value;
          got_year = true;

        } else if (!got_hour) {
          t.tm_hour = value;
          got_hour = true;

        } else if (!got_minute) {
          t.tm_min = value;
          got_minute = true;

        } else if (!got_second) {
          t.tm_sec = value;
          got_second = true;

        } else {
          // Huh, an unexpected numeric value.
          return;
        }
      }

    } else {
      // This is a string token.  It should be either a month name or
      // a day name, or a timezone name--but the only timezone name we
      // expect to see is "GMT".
      bool matched = false;
      int i;

      for (i = 0; i < num_weekdays && !matched; i++) {
        if (token == weekdays[i]) {
          if (got_weekday) {
            return;
          }
          matched = true;
          got_weekday = true;
          t.tm_wday = i;
        }
      }

      for (i = 0; i < num_months && !matched; i++) {
        if (token == months[i]) {
          if (got_month) {
            return;
          }
          matched = true;
          got_month = true;
          t.tm_mon = i;
        }
      }

      if (!matched && token == "Gmt") {
        matched = true;
        got_timezone = true;
      }

      if (!matched) {
        // Couldn't figure this one out.
        return;
      }
    }

    token = get_token(format, pos);
  }

  // Now check that we got the minimum expected tokens.
  if (!(got_month && got_day && got_year && got_hour && got_minute)) {
    return;
  }

  // Also validate the tokens we did get.
  if (t.tm_year < 100) {
    // Two-digit year.  Assume it's in the same century, unless
    // that assumption puts it more than 50 years in the future.
    time_t now = time(NULL);
    struct tm *tp = gmtime(&now);
    t.tm_year += 100 * (tp->tm_year / 100);
    if (t.tm_year - tp->tm_year > 50) {
      t.tm_year -= 100;
    }

  } else if (t.tm_year < 1900) {
    // Invalid three- or four-digit year.  Give up.
    return;

  } else {
    t.tm_year -= 1900;
  }

  if (!((t.tm_mon >= 0 && t.tm_mon < num_months) &&
        (t.tm_mday >= 1 && t.tm_mday <= 31) &&
        (t.tm_hour >= 0 && t.tm_hour < 60) &&
        (t.tm_min >= 0 && t.tm_min < 60) &&
        (t.tm_sec >= 0 && t.tm_sec < 62) /* maybe leap seconds */)) {
    return;
  }

  // Everything checks out; convert the date.
  _time = mktime(&t);

  if (_time != (time_t)-1) {
    // Unfortunately, mktime() assumes local time; convert this back
    // to GMT.
    extern long int timezone;
    _time -= timezone;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::get_string
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
string HTTPDate::
get_string() const {
  if (!is_valid()) {
    return "Invalid Date";
  }

  struct tm *tp = gmtime(&_time);

  ostringstream result;
  result
    << weekdays[tp->tm_wday] << ", "
    << setw(2) << setfill('0') << tp->tm_mday << " "
    << months[tp->tm_mon] << " "
    << setw(4) << setfill('0') << tp->tm_year + 1900 << " "
    << setw(2) << setfill('0') << tp->tm_hour << ":"
    << setw(2) << setfill('0') << tp->tm_min << ":"
    << setw(2) << setfill('0') << tp->tm_sec << " GMT";

  return result.str();
}

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::input
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
bool HTTPDate::
input(istream &in) {
  (*this) = HTTPDate();

  // Extract out the quoted date string.
  char ch;
  in >> ch;
  if (ch != '"') {
    return false;
  }

  string date;
  ch = in.get();
  while (!in.fail() && !in.eof() && ch != '"') {
    date += ch;
    ch = in.get();
  }

  if (ch != '"') {
    return false;
  }

  (*this) = HTTPDate(date);
  return is_valid();
}

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::output
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
void HTTPDate::
output(ostream &out) const {
  // We put quotes around the string on output, so we can reliably
  // detect the end of the date string on input, above.
  out << '"' << get_string() << '"';
}

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::get_token
//       Access: Published
//  Description: Extracts the next token from the string starting at
//               the indicated position.  Returns the token and
//               updates pos.  When the last token has been extracted,
//               returns empty string.
//
//               A token is defined as a contiguous sequence of digits
//               or letters.  If it is a sequence of letters, the
//               function quietly truncates it to three letters before
//               returning, and forces the first letter to capital and
//               the second two to lowercase.  If it is a sequence of
//               digits, the function also returns the next character
//               following the last digit (unless it is a letter).
////////////////////////////////////////////////////////////////////
string HTTPDate::
get_token(const string &str, size_t &pos) {
  // Start by scanning for the first alphanumeric character.
  size_t start = pos;
  while (start < str.length() && !isalnum(str[start])) {
    start++;
  }

  if (start >= str.length()) {
    // End of the line.
    pos = string::npos;
    return string();
  }

  string token;

  if (isalpha(str[start])) {
    // A string of letters.
    token = toupper(str[start]);
    pos = start + 1;
    while (pos < str.length() && isalpha(str[pos])) {
      if (token.length() < 3) {
        token += tolower(str[pos]);
      }
      pos++;
    }

  } else {
    // A string of digits.
    pos = start + 1;
    while (pos < str.length() && isdigit(str[pos])) {
      pos++;
    }
    // Get one more character, so we can identify things like hh:
    if (pos < str.length() && !isalpha(str[pos])) {
      pos++;
    }
    token = str.substr(start, pos - start);
  }

  return token;
}
<commit_msg>windows stupidity<commit_after>// Filename: httpDate.cxx
// Created by:  drose (28Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////

#include "httpDate.h"

#include <ctype.h>

static const int num_weekdays = 7;
static const char * const weekdays[num_weekdays] = {
  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

static const int num_months = 12;
static const char * const months[num_months] = {
  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::Constructor
//       Access: Published
//  Description: Decodes the string into a sensible date.  Returns 0
//               (!is_valid()) if the string cannot be correctly
//               decoded.
////////////////////////////////////////////////////////////////////
HTTPDate::
HTTPDate(const string &format) {
  _time = (time_t)(-1);

  struct tm t;
  memset(&t, 0, sizeof(t));

  bool got_weekday = false;
  bool got_month = false;
  bool got_day = false;
  bool got_year = false;
  bool got_hour = false;
  bool got_minute = false;
  bool got_second = false;
  bool got_timezone = false;

  enum ExpectNext {
    EN_none,
    EN_second,
    EN_year
  };
  ExpectNext expect_next = EN_none;

  size_t pos = 0;
  string token = get_token(format, pos);
  while (!token.empty()) {
    ExpectNext expected = expect_next;
    expect_next = EN_none;

    if (isdigit(token[0])) {
      // Here's a number.
      int value = atoi(token.c_str());
      if (token[token.length() - 1] == ':') {
        // If it ends in a colon, it must be hh or mm.
        if (!got_hour) {
          t.tm_hour = value;
          got_hour = true;

        } else if (!got_minute) {
          t.tm_min = value;
          got_minute = true;
          expect_next = EN_second;

        } else {
          return;
        }

      } else if (token[token.length() - 1] == '/') {
        // If it ends in a colon, it must be mm/dd/.
        if (!got_month) {
          t.tm_mon = value - 1;
          got_month = true;

        } else if (!got_day) {
          t.tm_mday = value;
          got_day = true;
          expect_next = EN_year;

        } else {
          return;
        }

      } else {
        if (expected == EN_second) {
          // The first number following hh:mm: is always the seconds.
          t.tm_sec = value;
          got_second = true;

        } else if (expected == EN_year) {
          // The first number following mm/dd/ is always the year.
          t.tm_year = value;
          got_year = true;

        } else if (!got_day) {
          // Assume it's a day.
          t.tm_mday = value;
          got_day = true;

        } else if (!got_year) {
          // It must be the year.
          t.tm_year = value;
          got_year = true;

        } else if (!got_hour) {
          t.tm_hour = value;
          got_hour = true;

        } else if (!got_minute) {
          t.tm_min = value;
          got_minute = true;

        } else if (!got_second) {
          t.tm_sec = value;
          got_second = true;

        } else {
          // Huh, an unexpected numeric value.
          return;
        }
      }

    } else {
      // This is a string token.  It should be either a month name or
      // a day name, or a timezone name--but the only timezone name we
      // expect to see is "GMT".
      bool matched = false;
      int i;

      for (i = 0; i < num_weekdays && !matched; i++) {
        if (token == weekdays[i]) {
          if (got_weekday) {
            return;
          }
          matched = true;
          got_weekday = true;
          t.tm_wday = i;
        }
      }

      for (i = 0; i < num_months && !matched; i++) {
        if (token == months[i]) {
          if (got_month) {
            return;
          }
          matched = true;
          got_month = true;
          t.tm_mon = i;
        }
      }

      if (!matched && token == "Gmt") {
        matched = true;
        got_timezone = true;
      }

      if (!matched) {
        // Couldn't figure this one out.
        return;
      }
    }

    token = get_token(format, pos);
  }

  // Now check that we got the minimum expected tokens.
  if (!(got_month && got_day && got_year && got_hour && got_minute)) {
    return;
  }

  // Also validate the tokens we did get.
  if (t.tm_year < 100) {
    // Two-digit year.  Assume it's in the same century, unless
    // that assumption puts it more than 50 years in the future.
    time_t now = time(NULL);
    struct tm *tp = gmtime(&now);
    t.tm_year += 100 * (tp->tm_year / 100);
    if (t.tm_year - tp->tm_year > 50) {
      t.tm_year -= 100;
    }

  } else if (t.tm_year < 1900) {
    // Invalid three- or four-digit year.  Give up.
    return;

  } else {
    t.tm_year -= 1900;
  }

  if (!((t.tm_mon >= 0 && t.tm_mon < num_months) &&
        (t.tm_mday >= 1 && t.tm_mday <= 31) &&
        (t.tm_hour >= 0 && t.tm_hour < 60) &&
        (t.tm_min >= 0 && t.tm_min < 60) &&
        (t.tm_sec >= 0 && t.tm_sec < 62) /* maybe leap seconds */)) {
    return;
  }

  // Everything checks out; convert the date.
  _time = mktime(&t);

  if (_time != (time_t)-1) {
    // Unfortunately, mktime() assumes local time; convert this back
    // to GMT.
    extern long int timezone;
    _time -= timezone;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::get_string
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
string HTTPDate::
get_string() const {
  if (!is_valid()) {
    return "Invalid Date";
  }

  struct tm *tp = gmtime(&_time);

  ostringstream result;
  result
    << weekdays[tp->tm_wday] << ", "
    << setw(2) << setfill('0') << tp->tm_mday << " "
    << months[tp->tm_mon] << " "
    << setw(4) << setfill('0') << tp->tm_year + 1900 << " "
    << setw(2) << setfill('0') << tp->tm_hour << ":"
    << setw(2) << setfill('0') << tp->tm_min << ":"
    << setw(2) << setfill('0') << tp->tm_sec << " GMT";

  return result.str();
}

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::input
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
bool HTTPDate::
input(istream &in) {
  (*this) = HTTPDate();

  // Extract out the quoted date string.
  char ch;
  in >> ch;
  if (ch != '"') {
    return false;
  }

  string date;
  ch = in.get();
  while (!in.fail() && !in.eof() && ch != '"') {
    date += ch;
    ch = in.get();
  }

  if (ch != '"') {
    return false;
  }

  // Visual C++ has problems with "(*this) = HTTPDate(date)".
  HTTPDate new_date(date);
  (*this) = new_date;
  return is_valid();
}

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::output
//       Access: Published
//  Description:
////////////////////////////////////////////////////////////////////
void HTTPDate::
output(ostream &out) const {
  // We put quotes around the string on output, so we can reliably
  // detect the end of the date string on input, above.
  out << '"' << get_string() << '"';
}

////////////////////////////////////////////////////////////////////
//     Function: HTTPDate::get_token
//       Access: Published
//  Description: Extracts the next token from the string starting at
//               the indicated position.  Returns the token and
//               updates pos.  When the last token has been extracted,
//               returns empty string.
//
//               A token is defined as a contiguous sequence of digits
//               or letters.  If it is a sequence of letters, the
//               function quietly truncates it to three letters before
//               returning, and forces the first letter to capital and
//               the second two to lowercase.  If it is a sequence of
//               digits, the function also returns the next character
//               following the last digit (unless it is a letter).
////////////////////////////////////////////////////////////////////
string HTTPDate::
get_token(const string &str, size_t &pos) {
  // Start by scanning for the first alphanumeric character.
  size_t start = pos;
  while (start < str.length() && !isalnum(str[start])) {
    start++;
  }

  if (start >= str.length()) {
    // End of the line.
    pos = string::npos;
    return string();
  }

  string token;

  if (isalpha(str[start])) {
    // A string of letters.
    token = toupper(str[start]);
    pos = start + 1;
    while (pos < str.length() && isalpha(str[pos])) {
      if (token.length() < 3) {
        token += tolower(str[pos]);
      }
      pos++;
    }

  } else {
    // A string of digits.
    pos = start + 1;
    while (pos < str.length() && isdigit(str[pos])) {
      pos++;
    }
    // Get one more character, so we can identify things like hh:
    if (pos < str.length() && !isalpha(str[pos])) {
      pos++;
    }
    token = str.substr(start, pos - start);
  }

  return token;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <unordered_map>
#include <ctime>

int main(int argc, char* argv[])
{
	if (argc != 5)
	{
		std::cerr << "Path Finder only accepts 4 arguments\n";
		exit(1);
	}

	// Load in all page titles into a vector
	std::cout << "\033[92m==>\033[0m Reading in page titles as a vector & map\n";

	std::vector<std::string> pages;
	std::unordered_map<std::string, int> page_ids;

	{
		std::clock_t start = std::clock();

		std::ifstream page_titles_file(argv[1]);
		std::string page_name;

		// We won't be using the first index of the vector for anything since
		// the page_id indexes start at 1 instead of 0. This should help to
		// prevent any errors during devlopment
		pages.push_back("");

		// Read the page name into the vector and into the hash-map
		int index = 1;

		while (std::getline(page_titles_file, page_name))
		{
			pages.push_back(page_name);
			page_ids[page_name] = index++;
		}
		std::cout << "\033[94m  -> \033[0mRead in " << index - 1 << " page titles\n";

		double duration = (std::clock() - start) / (double) CLOCKS_PER_SEC;
		std::cout << "\033[94m  -> \033[0mtook " << duration << " seconds\n";
	}

	return 0;
}

<commit_msg>Read in the links (in a inefficient way)<commit_after>#include <stdio.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
#include <unordered_map>
#include <ctime>

int main(int argc, char* argv[])
{
	if (argc != 5)
	{
		std::cerr << "Path Finder only accepts 4 arguments\n";
		exit(1);
	}

	// Load in all page titles into a vector
	std::cout << "\033[92m==>\033[0m Reading in page titles as a vector & map\n";

	std::vector<std::string> pages;
	std::unordered_map<std::string, int> page_ids;

	{
		std::clock_t start = std::clock();

		std::ifstream page_titles_file(argv[1]);
		std::string page_name;

		// We won't be using the first index of the vector for anything since
		// the page_id indexes start at 1 instead of 0. This should help to
		// prevent any errors during devlopment
		pages.push_back("");

		// Read the page name into the vector and into the hash-map
		int index = 1;

		while (std::getline(page_titles_file, page_name))
		{
			pages.push_back(page_name);
			page_ids[page_name] = index++;
		}
		std::cout << "\033[94m  -> \033[0mRead in " << index - 1 << " page titles\n";

		double duration = (std::clock() - start) / (double) CLOCKS_PER_SEC;
		std::cout << "\033[94m  -> \033[0mtook " << duration << " seconds\n";
	}

	// Load in all page links into a hash map
	std::cout << "\033[92m==>\033[0m Reading in page links as a map\n";

	std::unordered_map<int,std::vector<int>> page_links;

	{
		std::clock_t start = std::clock();

		std::ifstream page_links_file(argv[2]);
		std::string links;

		while (std::getline(page_links_file, links))
		{
			int split_at = links.find(':');
			int link_id = atoi(links.substr(0, split_at).c_str());
			links = links.substr(split_at + 2);

			std::stringstream stream_links(links);
			int target_id;

			while (stream_links >> target_id)
			{
				page_links[link_id].push_back(target_id);
			}
		}

		double duration = (std::clock() - start) / (double) CLOCKS_PER_SEC;
		std::cout << "\033[94m  -> \033[0mtook " << duration << " seconds\n";
	}

	int page_id = page_ids[argv[3]];
	std::cout << argv[3] << "(" << page_id << ") links to:\n";

	for (int i : page_links[page_id])
	{
		std::cout << " * " << pages[i] << std::endl;
	}

	return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "config.h"
#include "core/inspector/InspectorConsoleAgent.h"

#include "bindings/core/v8/ScriptCallStackFactory.h"
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptProfiler.h"
#include "core/frame/LocalFrame.h"
#include "core/inspector/InjectedScriptHost.h"
#include "core/inspector/InjectedScriptManager.h"
#include "core/inspector/InspectorConsoleMessage.h"
#include "core/inspector/InspectorState.h"
#include "core/inspector/InspectorTimelineAgent.h"
#include "core/inspector/InstrumentingAgents.h"
#include "core/inspector/ScriptArguments.h"
#include "core/inspector/ScriptCallFrame.h"
#include "core/inspector/ScriptCallStack.h"
#include "core/loader/DocumentLoader.h"
#include "core/page/Page.h"
#include "platform/network/ResourceError.h"
#include "platform/network/ResourceResponse.h"
#include "wtf/CurrentTime.h"
#include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/WTFString.h"

namespace blink {

static const unsigned maximumConsoleMessages = 1000;
static const int expireConsoleMessagesStep = 100;

namespace ConsoleAgentState {
static const char monitoringXHR[] = "monitoringXHR";
static const char consoleMessagesEnabled[] = "consoleMessagesEnabled";
}

int InspectorConsoleAgent::s_enabledAgentCount = 0;

InspectorConsoleAgent::InspectorConsoleAgent(InspectorTimelineAgent* timelineAgent, InjectedScriptManager* injectedScriptManager)
    : InspectorBaseAgent<InspectorConsoleAgent>("Console")
    , m_timelineAgent(timelineAgent)
    , m_injectedScriptManager(injectedScriptManager)
    , m_frontend(0)
    , m_expiredConsoleMessageCount(0)
    , m_enabled(false)
{
}

InspectorConsoleAgent::~InspectorConsoleAgent()
{
#if !ENABLE(OILPAN)
    m_instrumentingAgents->setInspectorConsoleAgent(0);
#endif
}

void InspectorConsoleAgent::trace(Visitor* visitor)
{
    visitor->trace(m_timelineAgent);
    visitor->trace(m_injectedScriptManager);
    InspectorBaseAgent::trace(visitor);
}

void InspectorConsoleAgent::init()
{
    m_instrumentingAgents->setInspectorConsoleAgent(this);
}

void InspectorConsoleAgent::enable(ErrorString*)
{
    if (m_enabled)
        return;
    m_enabled = true;
    if (!s_enabledAgentCount)
        ScriptController::setCaptureCallStackForUncaughtExceptions(true);
    ++s_enabledAgentCount;

    m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, true);

    if (m_expiredConsoleMessageCount) {
        InspectorConsoleMessage expiredMessage(!isWorkerAgent(), OtherMessageSource, LogMessageType, WarningMessageLevel, String::format("%d console messages are not shown.", m_expiredConsoleMessageCount));
        expiredMessage.setTimestamp(0);
        expiredMessage.addToFrontend(m_frontend, m_injectedScriptManager, false);
    }

    size_t messageCount = m_consoleMessages.size();
    for (size_t i = 0; i < messageCount; ++i)
        m_consoleMessages[i]->addToFrontend(m_frontend, m_injectedScriptManager, false);
}

void InspectorConsoleAgent::disable(ErrorString*)
{
    if (!m_enabled)
        return;
    m_enabled = false;
    if (!(--s_enabledAgentCount))
        ScriptController::setCaptureCallStackForUncaughtExceptions(false);
    m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, false);
}

void InspectorConsoleAgent::clearMessages(ErrorString*)
{
    m_consoleMessages.clear();
    m_expiredConsoleMessageCount = 0;
    m_injectedScriptManager->releaseObjectGroup("console");
    if (m_frontend && m_enabled)
        m_frontend->messagesCleared();
}

void InspectorConsoleAgent::reset()
{
    ErrorString error;
    clearMessages(&error);
    m_times.clear();
    m_counts.clear();
}

void InspectorConsoleAgent::restore()
{
    if (m_state->getBoolean(ConsoleAgentState::consoleMessagesEnabled)) {
        m_frontend->messagesCleared();
        ErrorString error;
        enable(&error);
    }
}

void InspectorConsoleAgent::setFrontend(InspectorFrontend* frontend)
{
    m_frontend = frontend->console();
}

void InspectorConsoleAgent::clearFrontend()
{
    m_frontend = 0;
    String errorString;
    disable(&errorString);
}

void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack, unsigned long requestIdentifier)
{
    if (type == ClearMessageType) {
        ErrorString error;
        clearMessages(&error);
    }

    addConsoleMessage(adoptPtr(new InspectorConsoleMessage(!isWorkerAgent(), source, type, level, message, callStack, requestIdentifier)));
}

void InspectorConsoleAgent::addConsoleAPIMessageToConsole(MessageType type, MessageLevel level, const String& message, ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments, unsigned long requestIdentifier)
{
    if (type == ClearMessageType) {
        ErrorString error;
        clearMessages(&error);
    }

    addConsoleMessage(adoptPtr(new InspectorConsoleMessage(!isWorkerAgent(), ConsoleAPIMessageSource, type, level, message, arguments, scriptState, requestIdentifier)));
}

void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& scriptId, unsigned lineNumber, unsigned columnNumber, ScriptState* scriptState, unsigned long requestIdentifier)
{
    if (type == ClearMessageType) {
        ErrorString error;
        clearMessages(&error);
    }

    bool canGenerateCallStack = !isWorkerAgent() && m_frontend;
    addConsoleMessage(adoptPtr(new InspectorConsoleMessage(canGenerateCallStack, source, type, level, message, scriptId, lineNumber, columnNumber, scriptState, requestIdentifier)));
}

Vector<unsigned> InspectorConsoleAgent::consoleMessageArgumentCounts()
{
    Vector<unsigned> result(m_consoleMessages.size());
    for (size_t i = 0; i < m_consoleMessages.size(); i++)
        result[i] = m_consoleMessages[i]->argumentCount();
    return result;
}

void InspectorConsoleAgent::consoleTime(ExecutionContext*, const String& title)
{
    // Follow Firebug's behavior of requiring a title that is not null or
    // undefined for timing functions
    if (title.isNull())
        return;

    m_times.add(title, monotonicallyIncreasingTime());
}

void InspectorConsoleAgent::consoleTimeEnd(ExecutionContext*, const String& title, ScriptState* scriptState)
{
    // Follow Firebug's behavior of requiring a title that is not null or
    // undefined for timing functions
    if (title.isNull())
        return;

    HashMap<String, double>::iterator it = m_times.find(title);
    if (it == m_times.end())
        return;

    double startTime = it->value;
    m_times.remove(it);

    double elapsed = monotonicallyIncreasingTime() - startTime;
    String message = title + String::format(": %.3fms", elapsed * 1000);
    addConsoleAPIMessageToConsole(LogMessageType, DebugMessageLevel, message, scriptState, nullptr);
}

void InspectorConsoleAgent::consoleTimeline(ExecutionContext* context, const String& title, ScriptState* scriptState)
{
    m_timelineAgent->consoleTimeline(context, title, scriptState);
}

void InspectorConsoleAgent::consoleTimelineEnd(ExecutionContext* context, const String& title, ScriptState* scriptState)
{
    m_timelineAgent->consoleTimelineEnd(context, title, scriptState);
}

void InspectorConsoleAgent::consoleCount(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
{
    RefPtrWillBeRawPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(scriptState));
    const ScriptCallFrame& lastCaller = callStack->at(0);
    // Follow Firebug's behavior of counting with null and undefined title in
    // the same bucket as no argument
    String title;
    arguments->getFirstArgumentAsString(title);
    String identifier = title.isEmpty() ? String(lastCaller.sourceURL() + ':' + String::number(lastCaller.lineNumber()))
                                        : String(title + '@');

    HashCountedSet<String>::AddResult result = m_counts.add(identifier);
    String message = title + ": " + String::number(result.storedValue->value);
    addConsoleAPIMessageToConsole(LogMessageType, DebugMessageLevel, message, scriptState, nullptr);
}

void InspectorConsoleAgent::frameWindowDiscarded(LocalDOMWindow* window)
{
    size_t messageCount = m_consoleMessages.size();
    for (size_t i = 0; i < messageCount; ++i)
        m_consoleMessages[i]->windowCleared(window);
    m_injectedScriptManager->discardInjectedScriptsFor(window);
}

void InspectorConsoleAgent::didCommitLoad(LocalFrame* frame, DocumentLoader* loader)
{
    if (loader->frame() != frame->page()->mainFrame())
        return;
    reset();
}

void InspectorConsoleAgent::didFinishXHRLoading(XMLHttpRequest*, ThreadableLoaderClient*, unsigned long requestIdentifier, ScriptString, const AtomicString& method, const String& url, const String& sendURL, unsigned sendLineNumber)
{
    if (m_frontend && m_state->getBoolean(ConsoleAgentState::monitoringXHR)) {
        String message = "XHR finished loading: " + method + " \"" + url + "\".";
        addMessageToConsole(NetworkMessageSource, LogMessageType, DebugMessageLevel, message, sendURL, sendLineNumber, 0, 0, requestIdentifier);
    }
}

void InspectorConsoleAgent::didReceiveResourceResponse(LocalFrame*, unsigned long requestIdentifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
{
    if (!loader)
        return;
    if (response.httpStatusCode() >= 400) {
        String message = "Failed to load resource: the server responded with a status of " + String::number(response.httpStatusCode()) + " (" + response.httpStatusText() + ')';
        addMessageToConsole(NetworkMessageSource, LogMessageType, ErrorMessageLevel, message, response.url().string(), 0, 0, 0, requestIdentifier);
    }
}

void InspectorConsoleAgent::didFailLoading(unsigned long requestIdentifier, const ResourceError& error)
{
    if (error.isCancellation()) // Report failures only.
        return;
    StringBuilder message;
    message.appendLiteral("Failed to load resource");
    if (!error.localizedDescription().isEmpty()) {
        message.appendLiteral(": ");
        message.append(error.localizedDescription());
    }
    addMessageToConsole(NetworkMessageSource, LogMessageType, ErrorMessageLevel, message.toString(), error.failingURL(), 0, 0, 0, requestIdentifier);
}

void InspectorConsoleAgent::setMonitoringXHREnabled(ErrorString*, bool enabled)
{
    m_state->setBoolean(ConsoleAgentState::monitoringXHR, enabled);
}

void InspectorConsoleAgent::addConsoleMessage(PassOwnPtr<InspectorConsoleMessage> consoleMessage)
{
    ASSERT_ARG(consoleMessage, consoleMessage);

    if (m_frontend && m_enabled)
        consoleMessage->addToFrontend(m_frontend, m_injectedScriptManager, true);

    m_consoleMessages.append(consoleMessage);

    if (!m_frontend && m_consoleMessages.size() >= maximumConsoleMessages) {
        m_expiredConsoleMessageCount += expireConsoleMessagesStep;
        m_consoleMessages.remove(0, expireConsoleMessagesStep);
    }
}

class InspectableHeapObject FINAL : public InjectedScriptHost::InspectableObject {
public:
    explicit InspectableHeapObject(int heapObjectId) : m_heapObjectId(heapObjectId) { }
    virtual ScriptValue get(ScriptState*) OVERRIDE
    {
        return ScriptProfiler::objectByHeapObjectId(m_heapObjectId);
    }
private:
    int m_heapObjectId;
};

void InspectorConsoleAgent::addInspectedHeapObject(ErrorString*, int inspectedHeapObjectId)
{
    m_injectedScriptManager->injectedScriptHost()->addInspectedObject(adoptPtr(new InspectableHeapObject(inspectedHeapObjectId)));
}

} // namespace blink

<commit_msg>DevTools: nits: collect only top call frame in InspectorConsoleAgent::consoleCount.<commit_after>/*
 * Copyright (C) 2011 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "config.h"
#include "core/inspector/InspectorConsoleAgent.h"

#include "bindings/core/v8/ScriptCallStackFactory.h"
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptProfiler.h"
#include "core/frame/LocalFrame.h"
#include "core/inspector/InjectedScriptHost.h"
#include "core/inspector/InjectedScriptManager.h"
#include "core/inspector/InspectorConsoleMessage.h"
#include "core/inspector/InspectorState.h"
#include "core/inspector/InspectorTimelineAgent.h"
#include "core/inspector/InstrumentingAgents.h"
#include "core/inspector/ScriptArguments.h"
#include "core/inspector/ScriptCallFrame.h"
#include "core/inspector/ScriptCallStack.h"
#include "core/loader/DocumentLoader.h"
#include "core/page/Page.h"
#include "platform/network/ResourceError.h"
#include "platform/network/ResourceResponse.h"
#include "wtf/CurrentTime.h"
#include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/WTFString.h"

namespace blink {

static const unsigned maximumConsoleMessages = 1000;
static const int expireConsoleMessagesStep = 100;

namespace ConsoleAgentState {
static const char monitoringXHR[] = "monitoringXHR";
static const char consoleMessagesEnabled[] = "consoleMessagesEnabled";
}

int InspectorConsoleAgent::s_enabledAgentCount = 0;

InspectorConsoleAgent::InspectorConsoleAgent(InspectorTimelineAgent* timelineAgent, InjectedScriptManager* injectedScriptManager)
    : InspectorBaseAgent<InspectorConsoleAgent>("Console")
    , m_timelineAgent(timelineAgent)
    , m_injectedScriptManager(injectedScriptManager)
    , m_frontend(0)
    , m_expiredConsoleMessageCount(0)
    , m_enabled(false)
{
}

InspectorConsoleAgent::~InspectorConsoleAgent()
{
#if !ENABLE(OILPAN)
    m_instrumentingAgents->setInspectorConsoleAgent(0);
#endif
}

void InspectorConsoleAgent::trace(Visitor* visitor)
{
    visitor->trace(m_timelineAgent);
    visitor->trace(m_injectedScriptManager);
    InspectorBaseAgent::trace(visitor);
}

void InspectorConsoleAgent::init()
{
    m_instrumentingAgents->setInspectorConsoleAgent(this);
}

void InspectorConsoleAgent::enable(ErrorString*)
{
    if (m_enabled)
        return;
    m_enabled = true;
    if (!s_enabledAgentCount)
        ScriptController::setCaptureCallStackForUncaughtExceptions(true);
    ++s_enabledAgentCount;

    m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, true);

    if (m_expiredConsoleMessageCount) {
        InspectorConsoleMessage expiredMessage(!isWorkerAgent(), OtherMessageSource, LogMessageType, WarningMessageLevel, String::format("%d console messages are not shown.", m_expiredConsoleMessageCount));
        expiredMessage.setTimestamp(0);
        expiredMessage.addToFrontend(m_frontend, m_injectedScriptManager, false);
    }

    size_t messageCount = m_consoleMessages.size();
    for (size_t i = 0; i < messageCount; ++i)
        m_consoleMessages[i]->addToFrontend(m_frontend, m_injectedScriptManager, false);
}

void InspectorConsoleAgent::disable(ErrorString*)
{
    if (!m_enabled)
        return;
    m_enabled = false;
    if (!(--s_enabledAgentCount))
        ScriptController::setCaptureCallStackForUncaughtExceptions(false);
    m_state->setBoolean(ConsoleAgentState::consoleMessagesEnabled, false);
}

void InspectorConsoleAgent::clearMessages(ErrorString*)
{
    m_consoleMessages.clear();
    m_expiredConsoleMessageCount = 0;
    m_injectedScriptManager->releaseObjectGroup("console");
    if (m_frontend && m_enabled)
        m_frontend->messagesCleared();
}

void InspectorConsoleAgent::reset()
{
    ErrorString error;
    clearMessages(&error);
    m_times.clear();
    m_counts.clear();
}

void InspectorConsoleAgent::restore()
{
    if (m_state->getBoolean(ConsoleAgentState::consoleMessagesEnabled)) {
        m_frontend->messagesCleared();
        ErrorString error;
        enable(&error);
    }
}

void InspectorConsoleAgent::setFrontend(InspectorFrontend* frontend)
{
    m_frontend = frontend->console();
}

void InspectorConsoleAgent::clearFrontend()
{
    m_frontend = 0;
    String errorString;
    disable(&errorString);
}

void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack, unsigned long requestIdentifier)
{
    if (type == ClearMessageType) {
        ErrorString error;
        clearMessages(&error);
    }

    addConsoleMessage(adoptPtr(new InspectorConsoleMessage(!isWorkerAgent(), source, type, level, message, callStack, requestIdentifier)));
}

void InspectorConsoleAgent::addConsoleAPIMessageToConsole(MessageType type, MessageLevel level, const String& message, ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments, unsigned long requestIdentifier)
{
    if (type == ClearMessageType) {
        ErrorString error;
        clearMessages(&error);
    }

    addConsoleMessage(adoptPtr(new InspectorConsoleMessage(!isWorkerAgent(), ConsoleAPIMessageSource, type, level, message, arguments, scriptState, requestIdentifier)));
}

void InspectorConsoleAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& scriptId, unsigned lineNumber, unsigned columnNumber, ScriptState* scriptState, unsigned long requestIdentifier)
{
    if (type == ClearMessageType) {
        ErrorString error;
        clearMessages(&error);
    }

    bool canGenerateCallStack = !isWorkerAgent() && m_frontend;
    addConsoleMessage(adoptPtr(new InspectorConsoleMessage(canGenerateCallStack, source, type, level, message, scriptId, lineNumber, columnNumber, scriptState, requestIdentifier)));
}

Vector<unsigned> InspectorConsoleAgent::consoleMessageArgumentCounts()
{
    Vector<unsigned> result(m_consoleMessages.size());
    for (size_t i = 0; i < m_consoleMessages.size(); i++)
        result[i] = m_consoleMessages[i]->argumentCount();
    return result;
}

void InspectorConsoleAgent::consoleTime(ExecutionContext*, const String& title)
{
    // Follow Firebug's behavior of requiring a title that is not null or
    // undefined for timing functions
    if (title.isNull())
        return;

    m_times.add(title, monotonicallyIncreasingTime());
}

void InspectorConsoleAgent::consoleTimeEnd(ExecutionContext*, const String& title, ScriptState* scriptState)
{
    // Follow Firebug's behavior of requiring a title that is not null or
    // undefined for timing functions
    if (title.isNull())
        return;

    HashMap<String, double>::iterator it = m_times.find(title);
    if (it == m_times.end())
        return;

    double startTime = it->value;
    m_times.remove(it);

    double elapsed = monotonicallyIncreasingTime() - startTime;
    String message = title + String::format(": %.3fms", elapsed * 1000);
    addConsoleAPIMessageToConsole(LogMessageType, DebugMessageLevel, message, scriptState, nullptr);
}

void InspectorConsoleAgent::consoleTimeline(ExecutionContext* context, const String& title, ScriptState* scriptState)
{
    m_timelineAgent->consoleTimeline(context, title, scriptState);
}

void InspectorConsoleAgent::consoleTimelineEnd(ExecutionContext* context, const String& title, ScriptState* scriptState)
{
    m_timelineAgent->consoleTimelineEnd(context, title, scriptState);
}

void InspectorConsoleAgent::consoleCount(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
{
    RefPtrWillBeRawPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(scriptState, 1));
    const ScriptCallFrame& lastCaller = callStack->at(0);
    // Follow Firebug's behavior of counting with null and undefined title in
    // the same bucket as no argument
    String title;
    arguments->getFirstArgumentAsString(title);
    String identifier = title.isEmpty() ? String(lastCaller.sourceURL() + ':' + String::number(lastCaller.lineNumber()))
                                        : String(title + '@');

    HashCountedSet<String>::AddResult result = m_counts.add(identifier);
    String message = title + ": " + String::number(result.storedValue->value);
    addConsoleAPIMessageToConsole(LogMessageType, DebugMessageLevel, message, scriptState, nullptr);
}

void InspectorConsoleAgent::frameWindowDiscarded(LocalDOMWindow* window)
{
    size_t messageCount = m_consoleMessages.size();
    for (size_t i = 0; i < messageCount; ++i)
        m_consoleMessages[i]->windowCleared(window);
    m_injectedScriptManager->discardInjectedScriptsFor(window);
}

void InspectorConsoleAgent::didCommitLoad(LocalFrame* frame, DocumentLoader* loader)
{
    if (loader->frame() != frame->page()->mainFrame())
        return;
    reset();
}

void InspectorConsoleAgent::didFinishXHRLoading(XMLHttpRequest*, ThreadableLoaderClient*, unsigned long requestIdentifier, ScriptString, const AtomicString& method, const String& url, const String& sendURL, unsigned sendLineNumber)
{
    if (m_frontend && m_state->getBoolean(ConsoleAgentState::monitoringXHR)) {
        String message = "XHR finished loading: " + method + " \"" + url + "\".";
        addMessageToConsole(NetworkMessageSource, LogMessageType, DebugMessageLevel, message, sendURL, sendLineNumber, 0, 0, requestIdentifier);
    }
}

void InspectorConsoleAgent::didReceiveResourceResponse(LocalFrame*, unsigned long requestIdentifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
{
    if (!loader)
        return;
    if (response.httpStatusCode() >= 400) {
        String message = "Failed to load resource: the server responded with a status of " + String::number(response.httpStatusCode()) + " (" + response.httpStatusText() + ')';
        addMessageToConsole(NetworkMessageSource, LogMessageType, ErrorMessageLevel, message, response.url().string(), 0, 0, 0, requestIdentifier);
    }
}

void InspectorConsoleAgent::didFailLoading(unsigned long requestIdentifier, const ResourceError& error)
{
    if (error.isCancellation()) // Report failures only.
        return;
    StringBuilder message;
    message.appendLiteral("Failed to load resource");
    if (!error.localizedDescription().isEmpty()) {
        message.appendLiteral(": ");
        message.append(error.localizedDescription());
    }
    addMessageToConsole(NetworkMessageSource, LogMessageType, ErrorMessageLevel, message.toString(), error.failingURL(), 0, 0, 0, requestIdentifier);
}

void InspectorConsoleAgent::setMonitoringXHREnabled(ErrorString*, bool enabled)
{
    m_state->setBoolean(ConsoleAgentState::monitoringXHR, enabled);
}

void InspectorConsoleAgent::addConsoleMessage(PassOwnPtr<InspectorConsoleMessage> consoleMessage)
{
    ASSERT_ARG(consoleMessage, consoleMessage);

    if (m_frontend && m_enabled)
        consoleMessage->addToFrontend(m_frontend, m_injectedScriptManager, true);

    m_consoleMessages.append(consoleMessage);

    if (!m_frontend && m_consoleMessages.size() >= maximumConsoleMessages) {
        m_expiredConsoleMessageCount += expireConsoleMessagesStep;
        m_consoleMessages.remove(0, expireConsoleMessagesStep);
    }
}

class InspectableHeapObject FINAL : public InjectedScriptHost::InspectableObject {
public:
    explicit InspectableHeapObject(int heapObjectId) : m_heapObjectId(heapObjectId) { }
    virtual ScriptValue get(ScriptState*) OVERRIDE
    {
        return ScriptProfiler::objectByHeapObjectId(m_heapObjectId);
    }
private:
    int m_heapObjectId;
};

void InspectorConsoleAgent::addInspectedHeapObject(ErrorString*, int inspectedHeapObjectId)
{
    m_injectedScriptManager->injectedScriptHost()->addInspectedObject(adoptPtr(new InspectableHeapObject(inspectedHeapObjectId)));
}

} // namespace blink

<|endoftext|>


<commit_before>#define WIN32_LEAN_AND_MEAN

#include <SDKDDKVer.h>
#include <windows.h>
#include "HookAPI.h"
#include <ws2tcpip.h>
#include <atomic>
#include <concurrent_queue.h>

#pragma comment (lib, "Ws2_32.lib")

#define BUFLEN 4096

// Socket used for TeamSpeak communication
std::atomic<SOCKET> client = NULL;
// Lua state used when requiring script files
std::atomic<lua_State *> state = NULL;
// Boolean telling the socket thread whether to keep the network loop running
std::atomic<bool> running = FALSE;
// Queue of commands to be sent to the Lua script
Concurrency::concurrent_queue<char *> queue;

// Tries to connect to TeamSpeak using ClientQuery
// Returns a new socket or NULL on failure

SOCKET Connect(PCSTR hostname, PCSTR port)
{
	// Creates a structure used for containing the socket information
	WSADATA wsaData;
	int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) return NULL;

	// Creates a structure used for containing the connection information
	struct addrinfo *info, *ptr, hints;
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	result = getaddrinfo(hostname, port, &hints, &info);
	if (result != 0)
	{
		WSACleanup();
		return NULL;
	}

	// Tries to connect to the specified address
	SOCKET client = INVALID_SOCKET;
	for (ptr = info; ptr != NULL; ptr = ptr->ai_next)
	{
		client = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
		if (client == INVALID_SOCKET)
		{
			WSACleanup();
			return NULL;
		}
		result = connect(client, ptr->ai_addr, (int)ptr->ai_addrlen);
		if (result == SOCKET_ERROR)
		{
			closesocket(client);
			client = INVALID_SOCKET;
			continue;
		}
		break;
	}

	// Releases the address information strcuture from memory
	freeaddrinfo(info);

	// Return NULL if the connection could not be established
	if (client == INVALID_SOCKET)
	{
		WSACleanup();
		return NULL;
	}

	// Sets keep alive to true for the socket
	char value = 1;
	setsockopt(client, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value));

	return client;
}

// Socket thread
// Executes a loop reading messages and passing them to the Lua script

DWORD WINAPI Main(LPVOID param)
{
	int length;
	char buffer[BUFLEN];
	char *ptr, *context;
	const char *separator = "\n\r";
	const char *command = "clientnotifyregister schandlerid=0 event=any\n";

	// Starts the network loop
	for (running = true; running; )
	{
		// Connects to the local TeamSpeak ClientQuery and retries on failure
		client = Connect("127.0.0.1", "25639");
		if (client == NULL) continue;

		// Receives the initial ClientQuery headers
		for (int header = 182; header > 0; header -= length)
			length = recv(client, buffer, BUFLEN, 0);

		// Sends a "listen to all events" command and receives it's response
		send(client, command, strlen(command), 0);
		recv(client, buffer, BUFLEN, 0);

		// Reads messages from the ClientQuery input stream
		do
		{
			// Receives a message and null terminates it
			buffer[length = recv(client, buffer, BUFLEN, 0)] = 0;
			// Splits up different messages that might be in the same buffer
			ptr = strtok_s(buffer, separator, &context);
			while (ptr != NULL)
			{
				// Copies the messages to heap memory and saves them to a queue
				int length = strlen(ptr) + 1;
				char *queued = new char[length];
				strcpy_s(queued, length, ptr);
				queue.push(queued);
				ptr = strtok_s(NULL, separator, &context);
			}

		} while (length > 0 && running);

		// Once the connection is closed cleans up all of its resources
		client = NULL;
		closesocket(client);
		WSACleanup();
	}

	return 0;
}

// Called by the Lua script
// Sends a message using the ClientQuery socket

int SendCommand(lua_State *L)
{
	// Stops if the socket is not connected or no message has been sent
	if (client == NULL || lua_type(L, 1) == -1) return 0;

	// Reads the message and sends it
	const char *buffer = lua_tostring(L, 1);
	send(client, buffer, strlen(buffer), 0);
	send(client, "\n", 1, 0);
	return 0;
}

// Requires the TeamSpeak Lua script and loads it into the game

void WINAPI OnRequire(lua_State *L, LPCSTR file, LPVOID param)
{
	// If the required file matches any we need to override
	if (strcmp(file, "lib/managers/chatmanager") == 0)
	{
		// Load that file into the game
		if (luaL_loadfile(L, "TeamSpeak/TeamSpeak.lua") == 0)
		{
			// And execute it
			lua_pcall(L, 0, LUA_MULTRET, 0);

			// Indexes the global TeamSpeak variable
			lua_getglobal(L, "TeamSpeak");
			int index = lua_gettop(L);

			// Creates a function called Send that maps to a C++ function
			lua_pushcfunction(L, &SendCommand);
			lua_setfield(L, index, "Send");

			// Creates the network thread and saves the current Lua state
			if (state == NULL)
			{
				state = L;
				CreateThread(NULL, 0, Main, NULL, 0, NULL);
			}
		}
	}
}

// Runs on game ticks and sends messages from TeamSpeak to the Lua script

void WINAPI OnGameTick(lua_State *L, LPCSTR type, LPVOID param)
{
	// If the Lua state matches out initial script load state,
	// the tick type is an update tick and out message queue is not empty
	if (L == state && strcmp(type, "update") == 0 && !queue.empty())
	{
		char *message;

		// Indexes the global TeamSpeak variable
		lua_getglobal(L, "TeamSpeak");
		int index = lua_gettop(L);

		// And sends each message over to a Lua function
		while (queue.try_pop(message))
		{
			lua_getfield(L, index, "OnReceive");
			lua_pushlstring(L, message, strlen(message));
			lua_pcall(L, 1, 0, 0);
			delete[] message;
		}
	}
}

// DLL entry point

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		// Registers a callback for when the game requires an internal file
		RegisterCallback(REQUIRE_CALLBACK, &OnRequire, NULL);
		// Registers a callback for game ticks
		RegisterCallback(GAMETICK_CALLBACK, &OnGameTick, NULL);
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		// Stops the network loop
		running = FALSE;
		break;
	}
	return TRUE;
}
<commit_msg>fix TeamSpeak disconnect issue<commit_after>#define WIN32_LEAN_AND_MEAN

#include <SDKDDKVer.h>
#include <windows.h>
#include "HookAPI.h"
#include <ws2tcpip.h>
#include <atomic>
#include <concurrent_queue.h>

#pragma comment (lib, "Ws2_32.lib")

#define BUFLEN 4096

// Socket used for TeamSpeak communication
std::atomic<SOCKET> client = NULL;
// Lua state used when requiring script files
std::atomic<lua_State *> state = NULL;
// Boolean telling the socket thread whether to keep the network loop running
std::atomic<bool> running = FALSE;
// Queue of commands to be sent to the Lua script
Concurrency::concurrent_queue<char *> queue;

// Tries to connect to TeamSpeak using ClientQuery
// Returns a new socket or NULL on failure

SOCKET Connect(PCSTR hostname, PCSTR port)
{
	// Creates a structure used for containing the socket information
	WSADATA wsaData;
	int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) return NULL;

	// Creates a structure used for containing the connection information
	struct addrinfo *info, *ptr, hints;
	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	result = getaddrinfo(hostname, port, &hints, &info);
	if (result != 0)
	{
		WSACleanup();
		return NULL;
	}

	// Tries to connect to the specified address
	SOCKET client = INVALID_SOCKET;
	for (ptr = info; ptr != NULL; ptr = ptr->ai_next)
	{
		client = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
		if (client == INVALID_SOCKET)
		{
			WSACleanup();
			return NULL;
		}
		result = connect(client, ptr->ai_addr, (int)ptr->ai_addrlen);
		if (result == SOCKET_ERROR)
		{
			closesocket(client);
			client = INVALID_SOCKET;
			continue;
		}
		break;
	}

	// Releases the address information strcuture from memory
	freeaddrinfo(info);

	// Return NULL if the connection could not be established
	if (client == INVALID_SOCKET)
	{
		WSACleanup();
		return NULL;
	}

	// Sets keep alive to true for the socket
	char value = 1;
	setsockopt(client, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value));

	return client;
}

// Socket thread
// Executes a loop reading messages and passing them to the Lua script

DWORD WINAPI Main(LPVOID param)
{
	int length;
	char buffer[BUFLEN];
	char *ptr, *context;
	const char *separator = "\n\r";
	const char *command = "clientnotifyregister schandlerid=0 event=any\n";

	// Starts the network loop
	for (running = true; running; )
	{
		// Connects to the local TeamSpeak ClientQuery and retries on failure
		client = Connect("127.0.0.1", "25639");
		if (client == NULL) continue;

		// Receives the initial ClientQuery headers
		for (int header = 182; header > 0; header -= length)
			length = recv(client, buffer, BUFLEN, 0);

		// Sends a "listen to all events" command and receives it's response
		send(client, command, strlen(command), 0);
		recv(client, buffer, BUFLEN, 0);

		// Reads messages from the ClientQuery input stream
		do
		{
			// Receives a message and null terminates it
			buffer[length = recv(client, buffer, BUFLEN, 0)] = 0;
			// Splits up different messages that might be in the same buffer
			ptr = strtok_s(buffer, separator, &context);
			while (ptr != NULL)
			{
				// Copies the messages to heap memory and saves them to a queue
				int length = strlen(ptr) + 1;
				char *queued = new char[length];
				strcpy_s(queued, length, ptr);
				queue.push(queued);
				ptr = strtok_s(NULL, separator, &context);
			}

		} while (length > 0 && running);

		// Once the connection is closed cleans up all of its resources
		{
			SOCKET socket = client;
			client = NULL;
			closesocket(socket);
			WSACleanup();
		}
	}

	return 0;
}

// Called by the Lua script
// Sends a message using the ClientQuery socket

int SendCommand(lua_State *L)
{
	// Stops if the socket is not connected or no message has been sent
	if (client == NULL || lua_type(L, 1) == -1) return 0;

	// Reads the message and sends it
	const char *buffer = lua_tostring(L, 1);
	send(client, buffer, strlen(buffer), 0);
	send(client, "\n", 1, 0);
	return 0;
}

// Requires the TeamSpeak Lua script and loads it into the game

void WINAPI OnRequire(lua_State *L, LPCSTR file, LPVOID param)
{
	// If the required file matches any we need to override
	if (strcmp(file, "lib/managers/chatmanager") == 0)
	{
		// Load that file into the game
		if (luaL_loadfile(L, "TeamSpeak/TeamSpeak.lua") == 0)
		{
			// And execute it
			lua_pcall(L, 0, LUA_MULTRET, 0);

			// Indexes the global TeamSpeak variable
			lua_getglobal(L, "TeamSpeak");
			int index = lua_gettop(L);

			// Creates a function called Send that maps to a C++ function
			lua_pushcfunction(L, &SendCommand);
			lua_setfield(L, index, "Send");

			// Saves the current Lua state and creates the network thread
			state = L;
			if (!running) CreateThread(NULL, 0, Main, NULL, 0, NULL);
		}
	}
}

// Runs on game ticks and sends messages from TeamSpeak to the Lua script

void WINAPI OnGameTick(lua_State *L, LPCSTR type, LPVOID param)
{
	// If the Lua state matches out initial script load state,
	// the tick type is an update tick and out message queue is not empty
	if (L == state && strcmp(type, "update") == 0 && !queue.empty())
	{
		char *message;

		// Indexes the global TeamSpeak variable
		lua_getglobal(L, "TeamSpeak");
		int index = lua_gettop(L);

		// And sends each message over to a Lua function
		while (queue.try_pop(message))
		{
			lua_getfield(L, index, "OnReceive");
			lua_pushlstring(L, message, strlen(message));
			lua_pcall(L, 1, 0, 0);
			delete[] message;
		}
	}
}

// DLL entry point

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		// Registers a callback for when the game requires an internal file
		RegisterCallback(REQUIRE_CALLBACK, &OnRequire, NULL);
		// Registers a callback for game ticks
		RegisterCallback(GAMETICK_CALLBACK, &OnGameTick, NULL);
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		// Stops the network loop
		running = FALSE;
		break;
	}
	return TRUE;
}
<|endoftext|>


<commit_before>// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
extern "C" {
#include "PrtDist.h"
#include "test.h"
#include "Prt.h"
}
#include "DgmlGraphWriter.h"
#include <string>

/* Global variables */
PRT_PROCESS* ContainerProcess;
struct ClusterConfig ClusterConfiguration;
PRT_INT64 sendMessageSeqNumber = 0;
DgmlGraphWriter dgmlMonitor;

/* the Stubs */

typedef struct ClientContext {
    PRT_VALUE *client;
} ClientContext;

typedef struct ServerContext {
    PRT_VALUE *client;
} ServerContext;

void P_CTOR_Client_IMPL(PRT_MACHINEINST *context, PRT_VALUE *value)
{
    printf("Entering P_CTOR_Client_IMPL\n");
    ClientContext *clientContext = (ClientContext *)PrtMalloc(sizeof(ClientContext));
    clientContext->client = PrtCloneValue(value);
    context->extContext = clientContext;
}

void P_DTOR_Client_IMPL(PRT_MACHINEINST *context)
{
    printf("Entering P_DTOR_Client_IMPL\n");
    ClientContext *clientContext = (ClientContext *)context->extContext;
    PrtFreeValue(clientContext->client);
    PrtFree(clientContext);
}

void P_CTOR_Server_IMPL(PRT_MACHINEINST *context, PRT_VALUE *value)
{
    printf("Entering P_CTOR_Server_IMPL\n");
    ServerContext *serverContext = (ServerContext *)PrtMalloc(sizeof(ServerContext));
    serverContext->client = PrtCloneValue(value);
    context->extContext = serverContext;
}

void P_DTOR_Server_IMPL(PRT_MACHINEINST *context)
{
    printf("Entering P_DTOR_Server_IMPL\n");
    ServerContext *serverContext = (ServerContext *)context->extContext;
    PrtFreeValue(serverContext->client);
    PrtFree(serverContext);
}

void P_CTOR_Safety_IMPL(PRT_MACHINEINST *context, PRT_VALUE *value) {}

void P_DTOR_Safety_IMPL(PRT_MACHINEINST *context) {}

std::wstring ConvertToUnicode(const char* str)
{
	std::string temp(str == NULL ? "" : str);
	return std::wstring(temp.begin(), temp.end());
}

static void LogHandler(PRT_STEP step, PRT_MACHINEINST *sender, PRT_MACHINEINST *receiver, PRT_VALUE* event, PRT_VALUE* payload)
{
    // This LogHandler shows how to use the dgmlMonitor to create a DGML graph of the state machine transitions that
	// were recorded by this LogHandler.  The DGML identifiers computed below are designed to ensure the correct DGML graph is built.
	PRT_MACHINEINST_PRIV * c = (PRT_MACHINEINST_PRIV *)receiver;
	std::wstring machineName = ConvertToUnicode((const char*)c->process->program->machines[c->instanceOf]->name);
	PRT_UINT32 machineId = c->id->valueUnion.mid->machineId;
	std::wstring stateName;
	stateName = ConvertToUnicode((const char*)PrtGetCurrentStateDecl(c)->name);

	std::wstring eventName;
	std::wstring stateId = machineName + L"." + stateName;
	std::wstring stateLabel = machineName + L"\n" + stateName;
	std::wstring senderMachineName;
	std::wstring senderStateName;
	std::wstring senderStateId;
	std::wstring senderStateLabel;
	if (sender != NULL && event != NULL)
	{
		PRT_MACHINEINST_PRIV * s = (PRT_MACHINEINST_PRIV *)sender;
		eventName = ConvertToUnicode((const char*)s->process->program->events[PrtPrimGetEvent(event)].name);
		senderMachineName = ConvertToUnicode((const char*)s->process->program->machines[s->instanceOf]->name);
		senderStateName = ConvertToUnicode((const char*)PrtGetCurrentStateDecl(s)->name);
		senderStateId = senderMachineName + L"." + senderStateName;
		senderStateLabel = senderMachineName + L"\n" + senderStateName;
	}

	switch (step)
	{
	case PRT_STEP_HALT:
		dgmlMonitor.NavigateLink(stateId.c_str(), stateLabel.c_str(), stateId.c_str(), stateLabel.c_str(), L"halt", 0);
		break;
	case PRT_STEP_ENQUEUE:
		break;
	case PRT_STEP_DEQUEUE:
		dgmlMonitor.NavigateLink(senderStateId.c_str(), senderStateLabel.c_str(), stateId.c_str(), stateLabel.c_str(), eventName.c_str(), 0);
		break;
	case PRT_STEP_ENTRY:
		break;
	case PRT_STEP_CREATE:
		break;
	case PRT_STEP_RAISE:
		break;
	case PRT_STEP_POP:
		break;
	case PRT_STEP_PUSH:
		break;
	case PRT_STEP_UNHANDLED:
		break;
	case PRT_STEP_DO:
		break;
	case PRT_STEP_EXIT:
		break;
	case PRT_STEP_IGNORE:
		break;
	}

	SleepEx(1, TRUE); // SleepEx allows the Win32 Timer to execute.
}

/**
* The main function performs the following steps
* 1) If the createMain option is true then it create the main machine.
* 2) If the createMain option is false then it creates the Container machine.
* 3) It creates a RPC server to listen for messages.

Also note that the machine hosting the main machine does not host container machine.

**/

int main(int argc, char *argv[])
{
	bool dgml = false;
	bool cooperative = false;
	for (int i = 0; i < argc; i++)
	{
		char* arg = argv[i];
		if (arg[0] == '/' || arg[0] == '-')
		{
			char* name = arg + 1;
			if (strcmp(name, "dgml") == 0)
			{
				dgml = true;
			}
			else if (strcmp(name, "cooperative") == 0)
			{
				cooperative = true;
			}
		}
	}

	if (dgml) {

		// Attempt to connect to Visual Studio running on some machine.  This instance of VS 2015 needs to have the DgmlTestMonitor VSIX extension
		// installed, and the DgmlTestMonitor window needs to be open.  Then you will see the state machine building & animating in real time.
		// dgmlMonitor.Connect("10.137.62.126");

		// Either way you need to also start a new graph file on disk. If you have not connected to VS then this file will be written
		// at the time you call dgmlMonitor.Close(), otherwise VS will maintain the graph inside VS.
		dgmlMonitor.NewGraph(L"d:\\temp\\trace.dgml");
	}

    PRT_GUID processGuid;
    processGuid.data1 = 1;
    processGuid.data2 = 1; //nodeId
    processGuid.data3 = 0;
    processGuid.data4 = 0;
    ContainerProcess = PrtStartProcess(processGuid, &P_GEND_PROGRAM, PrtDistSMExceptionHandler, LogHandler);

	if (cooperative)
	{
		PrtSetSchedulingPolicy(ContainerProcess, PRT_SCHEDULINGPOLICY_COOPERATIVE);
	}

    //create main machine
    PrtMkMachine(ContainerProcess, P_MACHINE_Client, 0);
    PrtFreeValue(payload);

    // Wait for the timer.
	int iterations = 10;
    while (iterations--) {

		if (cooperative)
		{
			PrtRunProcess(ContainerProcess);
		}
		else {
			SleepEx(1000, TRUE); // SleepEx allows the Win32 Timer to execute.
		}
    }

	if (dgml) {
		dgmlMonitor.Close();
	}

    return 0;

}
<commit_msg>fix build break<commit_after>// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
extern "C" {
#include "PrtDist.h"
#include "test.h"
#include "Prt.h"
}
#include "DgmlGraphWriter.h"
#include <string>

/* Global variables */
PRT_PROCESS* ContainerProcess;
struct ClusterConfig ClusterConfiguration;
PRT_INT64 sendMessageSeqNumber = 0;
DgmlGraphWriter dgmlMonitor;

/* the Stubs */

typedef struct ClientContext {
    PRT_VALUE *client;
} ClientContext;

typedef struct ServerContext {
    PRT_VALUE *client;
} ServerContext;

void P_CTOR_Client_IMPL(PRT_MACHINEINST *context, PRT_VALUE *value)
{
    printf("Entering P_CTOR_Client_IMPL\n");
    ClientContext *clientContext = (ClientContext *)PrtMalloc(sizeof(ClientContext));
    clientContext->client = PrtCloneValue(value);
    context->extContext = clientContext;
}

void P_DTOR_Client_IMPL(PRT_MACHINEINST *context)
{
    printf("Entering P_DTOR_Client_IMPL\n");
    ClientContext *clientContext = (ClientContext *)context->extContext;
    PrtFreeValue(clientContext->client);
    PrtFree(clientContext);
}

void P_CTOR_Server_IMPL(PRT_MACHINEINST *context, PRT_VALUE *value)
{
    printf("Entering P_CTOR_Server_IMPL\n");
    ServerContext *serverContext = (ServerContext *)PrtMalloc(sizeof(ServerContext));
    serverContext->client = PrtCloneValue(value);
    context->extContext = serverContext;
}

void P_DTOR_Server_IMPL(PRT_MACHINEINST *context)
{
    printf("Entering P_DTOR_Server_IMPL\n");
    ServerContext *serverContext = (ServerContext *)context->extContext;
    PrtFreeValue(serverContext->client);
    PrtFree(serverContext);
}

void P_CTOR_Safety_IMPL(PRT_MACHINEINST *context, PRT_VALUE *value) {}

void P_DTOR_Safety_IMPL(PRT_MACHINEINST *context) {}

std::wstring ConvertToUnicode(const char* str)
{
	std::string temp(str == NULL ? "" : str);
	return std::wstring(temp.begin(), temp.end());
}

static void LogHandler(PRT_STEP step, PRT_MACHINEINST *sender, PRT_MACHINEINST *receiver, PRT_VALUE* event, PRT_VALUE* payload)
{
    // This LogHandler shows how to use the dgmlMonitor to create a DGML graph of the state machine transitions that
	// were recorded by this LogHandler.  The DGML identifiers computed below are designed to ensure the correct DGML graph is built.
	PRT_MACHINEINST_PRIV * c = (PRT_MACHINEINST_PRIV *)receiver;
	std::wstring machineName = ConvertToUnicode((const char*)c->process->program->machines[c->instanceOf]->name);
	PRT_UINT32 machineId = c->id->valueUnion.mid->machineId;
	std::wstring stateName;
	stateName = ConvertToUnicode((const char*)PrtGetCurrentStateDecl(c)->name);

	std::wstring eventName;
	std::wstring stateId = machineName + L"." + stateName;
	std::wstring stateLabel = machineName + L"\n" + stateName;
	std::wstring senderMachineName;
	std::wstring senderStateName;
	std::wstring senderStateId;
	std::wstring senderStateLabel;
	if (sender != NULL && event != NULL)
	{
		PRT_MACHINEINST_PRIV * s = (PRT_MACHINEINST_PRIV *)sender;
		eventName = ConvertToUnicode((const char*)s->process->program->events[PrtPrimGetEvent(event)].name);
		senderMachineName = ConvertToUnicode((const char*)s->process->program->machines[s->instanceOf]->name);
		senderStateName = ConvertToUnicode((const char*)PrtGetCurrentStateDecl(s)->name);
		senderStateId = senderMachineName + L"." + senderStateName;
		senderStateLabel = senderMachineName + L"\n" + senderStateName;
	}

	switch (step)
	{
	case PRT_STEP_HALT:
		dgmlMonitor.NavigateLink(stateId.c_str(), stateLabel.c_str(), stateId.c_str(), stateLabel.c_str(), L"halt", 0);
		break;
	case PRT_STEP_ENQUEUE:
		break;
	case PRT_STEP_DEQUEUE:
		dgmlMonitor.NavigateLink(senderStateId.c_str(), senderStateLabel.c_str(), stateId.c_str(), stateLabel.c_str(), eventName.c_str(), 0);
		break;
	case PRT_STEP_ENTRY:
		break;
	case PRT_STEP_CREATE:
		break;
	case PRT_STEP_RAISE:
		break;
	case PRT_STEP_POP:
		break;
	case PRT_STEP_PUSH:
		break;
	case PRT_STEP_UNHANDLED:
		break;
	case PRT_STEP_DO:
		break;
	case PRT_STEP_EXIT:
		break;
	case PRT_STEP_IGNORE:
		break;
	}

	SleepEx(1, TRUE); // SleepEx allows the Win32 Timer to execute.
}

/**
* The main function performs the following steps
* 1) If the createMain option is true then it create the main machine.
* 2) If the createMain option is false then it creates the Container machine.
* 3) It creates a RPC server to listen for messages.

Also note that the machine hosting the main machine does not host container machine.

**/

int main(int argc, char *argv[])
{
	bool dgml = false;
	bool cooperative = false;
	for (int i = 0; i < argc; i++)
	{
		char* arg = argv[i];
		if (arg[0] == '/' || arg[0] == '-')
		{
			char* name = arg + 1;
			if (strcmp(name, "dgml") == 0)
			{
				dgml = true;
			}
			else if (strcmp(name, "cooperative") == 0)
			{
				cooperative = true;
			}
		}
	}

	if (dgml) {

		// Attempt to connect to Visual Studio running on some machine.  This instance of VS 2015 needs to have the DgmlTestMonitor VSIX extension
		// installed, and the DgmlTestMonitor window needs to be open.  Then you will see the state machine building & animating in real time.
		// dgmlMonitor.Connect("10.137.62.126");

		// Either way you need to also start a new graph file on disk. If you have not connected to VS then this file will be written
		// at the time you call dgmlMonitor.Close(), otherwise VS will maintain the graph inside VS.
		dgmlMonitor.NewGraph(L"d:\\temp\\trace.dgml");
	}

    PRT_GUID processGuid;
    processGuid.data1 = 1;
    processGuid.data2 = 1; //nodeId
    processGuid.data3 = 0;
    processGuid.data4 = 0;
    ContainerProcess = PrtStartProcess(processGuid, &P_GEND_PROGRAM, PrtDistSMExceptionHandler, LogHandler);

	if (cooperative)
	{
		PrtSetSchedulingPolicy(ContainerProcess, PRT_SCHEDULINGPOLICY_COOPERATIVE);
	}

    //create main machine
    PrtMkMachine(ContainerProcess, P_MACHINE_Client, 0);

    // Wait for the timer.
	int iterations = 10;
    while (iterations--) {

		if (cooperative)
		{
			PrtRunProcess(ContainerProcess);
		}
		else {
			SleepEx(1000, TRUE); // SleepEx allows the Win32 Timer to execute.
		}
    }

	if (dgml) {
		dgmlMonitor.Close();
	}

    return 0;

}
<|endoftext|>