<commit_before>/* Copyright 2016 Google Inc. 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 "tensorflow_serving/resources/resource_tracker.h"

#include <algorithm>
#include <string>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/platform/google/integral_types.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow_serving/core/test_util/mock_loader.h"
#include "tensorflow_serving/resources/resources.pb.h"
#include "tensorflow_serving/test_util/test_util.h"
#include "tensorflow_serving/util/any_ptr.h"

using ::tensorflow::serving::test_util::CreateProto;
using ::tensorflow::serving::test_util::EqualsProto;
using ::testing::_;
using ::testing::Return;
using ::testing::NiceMock;

namespace tensorflow {
namespace serving {
namespace {

class ResourceTrackerTest : public ::testing::Test {
 protected:
  ResourceTrackerTest()
      : total_resources_(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'cpu' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 16 "
                                            "} "
                                            "resource_quantities { "
                                            "  resource { "
                                            "    device: 'gpu' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 16 "
                                            "} "
                                            "resource_quantities { "
                                            "  resource { "
                                            "    device: 'gpu' "
                                            "    device_instance { value: 1 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 16 "
                                            "} ")) {
    std::unique_ptr<ResourceUtil> util(
        new ResourceUtil({{{"cpu", 1}, {"gpu", 2}}}));
    TF_CHECK_OK(ResourceTracker::Create(
        total_resources_, std::unique_ptr<ResourceUtil>(std::move(util)),
        &tracker_));

    loader_0_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*loader_0_, EstimateResources())
        .WillByDefault(Return(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'cpu' "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 1 "
                                            "} "
                                            "resource_quantities { "
                                            "  resource { "
                                            "    device: 'gpu' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 3 "
                                            "} ")));

    loader_1_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*loader_1_, EstimateResources())
        .WillByDefault(Return(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'cpu' "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 5 "
                                            "} "
                                            "resource_quantities { "
                                            "  resource { "
                                            "    device: 'gpu' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 7 "
                                            "} ")));

    loader_2_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*loader_2_, EstimateResources())
        .WillByDefault(Return(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'cpu' "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 15 "
                                            "} ")));

    loader_3_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*loader_3_, EstimateResources())
        .WillByDefault(
            Return(CreateProto<ResourceAllocation>("resource_quantities { "
                                                   "  resource { "
                                                   "    device: 'gpu' "
                                                   "    kind: 'ram' "
                                                   "  } "
                                                   "  quantity: 12 "
                                                   "} ")));

    invalid_resources_loader_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*invalid_resources_loader_, EstimateResources())
        .WillByDefault(Return(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'bogus_device' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 4 "
                                            "} ")));

    // Disallow calls to Load()/Unload().
    for (auto* loader : {loader_0_.get(), loader_1_.get(), loader_2_.get(),
                         loader_3_.get(), invalid_resources_loader_.get()}) {
      EXPECT_CALL(*loader, Load(_)).Times(0);
      EXPECT_CALL(*loader, Unload()).Times(0);
    }
  }

  // The original total-resources valued provided to 'tracker_'.
  const ResourceAllocation total_resources_;

  // The object under testing.
  std::unique_ptr<ResourceTracker> tracker_;

  // Some mock loaders with specific resource estimates (see the constructor).
  std::unique_ptr<test_util::MockLoader> loader_0_;
  std::unique_ptr<test_util::MockLoader> loader_1_;
  std::unique_ptr<test_util::MockLoader> loader_2_;
  std::unique_ptr<test_util::MockLoader> loader_3_;
  std::unique_ptr<test_util::MockLoader> invalid_resources_loader_;
};

TEST_F(ResourceTrackerTest, UnboundTotalResources) {
  std::unique_ptr<ResourceUtil> util(
      new ResourceUtil({{{"cpu", 1}, {"gpu", 2}}}));
  std::unique_ptr<ResourceTracker> tracker;
  const auto unbound_resources = CreateProto<ResourceAllocation>(
      "resource_quantities { "
      "  resource { "
      "    device: 'gpu' "
      "    kind: 'ram' "
      "  } "
      "  quantity: 12 "
      "} ");
  EXPECT_FALSE(ResourceTracker::Create(
                   unbound_resources,
                   std::unique_ptr<ResourceUtil>(std::move(util)), &tracker)
                   .ok());
}

TEST_F(ResourceTrackerTest, UnnormalizedTotalResources) {
  std::unique_ptr<ResourceUtil> util(
      new ResourceUtil({{{"cpu", 1}, {"gpu", 2}}}));
  std::unique_ptr<ResourceTracker> tracker;
  const auto unnormalized_resources = CreateProto<ResourceAllocation>(
      "resource_quantities { "
      "  resource { "
      "    device: 'cpu' "
      "    kind: 'ram' "
      "  } "
      "  quantity: 12 "
      "} ");
  TF_ASSERT_OK(ResourceTracker::Create(
      unnormalized_resources, std::unique_ptr<ResourceUtil>(std::move(util)),
      &tracker));
  // The total_resources proto should get normalized.
  EXPECT_THAT(tracker->total_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 12 "
                          "} "));
}

TEST_F(ResourceTrackerTest, RecomputeUsedResources) {
  // Verify the initial state.
  EXPECT_THAT(tracker_->used_resources(), EqualsProto(""));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));

  // Recompute used resources for {loader_0_, loader_1_, loader_3_}.
  TF_ASSERT_OK(tracker_->RecomputeUsedResources(
      {loader_0_.get(), loader_1_.get(), loader_3_.get()}));
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 6 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 10 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 12 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));

  // Recompute used resources for just {loader_0_}.
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_0_.get()}));
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 1 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 3 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, ReserveResourcesSuccessWithUsedResourcesBound) {
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_0_.get()}));
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 1 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 3 "
                          "} "));

  // If just loader_0_ is loaded, loader_2_ should also fit.
  bool success;
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_2_, &success));
  EXPECT_TRUE(success);
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 16 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 3 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, ReserveResourcesFailureWithUsedResourcesBound) {
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_1_.get()}));
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 5 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 7 "
                          "} "));

  // If loader_1_ is loaded, there isn't room for loader_2_.
  bool success;
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_2_, &success));
  EXPECT_FALSE(success);
  // The used resources should remain unchanged (i.e. only reflect loader_1_).
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 5 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 7 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, ReserveResourcesSuccessWithUsedResourcesUnbound) {
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_3_.get()}));
  EXPECT_THAT(tracker_->used_resources(), EqualsProto("resource_quantities { "
                                                      "  resource { "
                                                      "    device: 'gpu' "
                                                      "    kind: 'ram' "
                                                      "  } "
                                                      "  quantity: 12 "
                                                      "} "));

  // If just loader_3_ is loaded, loader_0_ should also fit.
  bool success;
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_0_, &success));
  EXPECT_TRUE(success);
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 12 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 1 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 3 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, ReserveResourcesFailureWithUsedResourcesUnbound) {
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_3_.get()}));
  EXPECT_THAT(tracker_->used_resources(), EqualsProto("resource_quantities { "
                                                      "  resource { "
                                                      "    device: 'gpu' "
                                                      "    kind: 'ram' "
                                                      "  } "
                                                      "  quantity: 12 "
                                                      "} "));

  // If loader_3_ is loaded, there isn't room for loader_1_, or for another
  // copy of loader_3_.
  bool success;
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_1_, &success));
  EXPECT_FALSE(success);
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_3_, &success));
  EXPECT_FALSE(success);
  // The used resources should remain unchanged (i.e. only reflect a single copy
  // of loader_3_).
  EXPECT_THAT(tracker_->used_resources(), EqualsProto("resource_quantities { "
                                                      "  resource { "
                                                      "    device: 'gpu' "
                                                      "    kind: 'ram' "
                                                      "  } "
                                                      "  quantity: 12 "
                                                      "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, InvalidResourceEstimate) {
  bool success;
  EXPECT_FALSE(
      tracker_->ReserveResources(*invalid_resources_loader_, &success).ok());
  EXPECT_FALSE(tracker_
                   ->RecomputeUsedResources(
                       {loader_0_.get(), invalid_resources_loader_.get()})
                   .ok());
}

}  // namespace
}  // namespace serving
}  // namespace tensorflow
<commit_msg>Fix open source build. Change: 117845225<commit_after>/* Copyright 2016 Google Inc. 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 "tensorflow_serving/resources/resource_tracker.h"

#include <algorithm>
#include <string>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/status_test_util.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow_serving/core/test_util/mock_loader.h"
#include "tensorflow_serving/resources/resources.pb.h"
#include "tensorflow_serving/test_util/test_util.h"
#include "tensorflow_serving/util/any_ptr.h"

using ::tensorflow::serving::test_util::CreateProto;
using ::tensorflow::serving::test_util::EqualsProto;
using ::testing::_;
using ::testing::Return;
using ::testing::NiceMock;

namespace tensorflow {
namespace serving {
namespace {

class ResourceTrackerTest : public ::testing::Test {
 protected:
  ResourceTrackerTest()
      : total_resources_(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'cpu' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 16 "
                                            "} "
                                            "resource_quantities { "
                                            "  resource { "
                                            "    device: 'gpu' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 16 "
                                            "} "
                                            "resource_quantities { "
                                            "  resource { "
                                            "    device: 'gpu' "
                                            "    device_instance { value: 1 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 16 "
                                            "} ")) {
    std::unique_ptr<ResourceUtil> util(
        new ResourceUtil({{{"cpu", 1}, {"gpu", 2}}}));
    TF_CHECK_OK(ResourceTracker::Create(
        total_resources_, std::unique_ptr<ResourceUtil>(std::move(util)),
        &tracker_));

    loader_0_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*loader_0_, EstimateResources())
        .WillByDefault(Return(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'cpu' "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 1 "
                                            "} "
                                            "resource_quantities { "
                                            "  resource { "
                                            "    device: 'gpu' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 3 "
                                            "} ")));

    loader_1_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*loader_1_, EstimateResources())
        .WillByDefault(Return(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'cpu' "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 5 "
                                            "} "
                                            "resource_quantities { "
                                            "  resource { "
                                            "    device: 'gpu' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 7 "
                                            "} ")));

    loader_2_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*loader_2_, EstimateResources())
        .WillByDefault(Return(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'cpu' "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 15 "
                                            "} ")));

    loader_3_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*loader_3_, EstimateResources())
        .WillByDefault(
            Return(CreateProto<ResourceAllocation>("resource_quantities { "
                                                   "  resource { "
                                                   "    device: 'gpu' "
                                                   "    kind: 'ram' "
                                                   "  } "
                                                   "  quantity: 12 "
                                                   "} ")));

    invalid_resources_loader_.reset(new NiceMock<test_util::MockLoader>);
    ON_CALL(*invalid_resources_loader_, EstimateResources())
        .WillByDefault(Return(
            CreateProto<ResourceAllocation>("resource_quantities { "
                                            "  resource { "
                                            "    device: 'bogus_device' "
                                            "    device_instance { value: 0 } "
                                            "    kind: 'ram' "
                                            "  } "
                                            "  quantity: 4 "
                                            "} ")));

    // Disallow calls to Load()/Unload().
    for (auto* loader : {loader_0_.get(), loader_1_.get(), loader_2_.get(),
                         loader_3_.get(), invalid_resources_loader_.get()}) {
      EXPECT_CALL(*loader, Load(_)).Times(0);
      EXPECT_CALL(*loader, Unload()).Times(0);
    }
  }

  // The original total-resources valued provided to 'tracker_'.
  const ResourceAllocation total_resources_;

  // The object under testing.
  std::unique_ptr<ResourceTracker> tracker_;

  // Some mock loaders with specific resource estimates (see the constructor).
  std::unique_ptr<test_util::MockLoader> loader_0_;
  std::unique_ptr<test_util::MockLoader> loader_1_;
  std::unique_ptr<test_util::MockLoader> loader_2_;
  std::unique_ptr<test_util::MockLoader> loader_3_;
  std::unique_ptr<test_util::MockLoader> invalid_resources_loader_;
};

TEST_F(ResourceTrackerTest, UnboundTotalResources) {
  std::unique_ptr<ResourceUtil> util(
      new ResourceUtil({{{"cpu", 1}, {"gpu", 2}}}));
  std::unique_ptr<ResourceTracker> tracker;
  const auto unbound_resources = CreateProto<ResourceAllocation>(
      "resource_quantities { "
      "  resource { "
      "    device: 'gpu' "
      "    kind: 'ram' "
      "  } "
      "  quantity: 12 "
      "} ");
  EXPECT_FALSE(ResourceTracker::Create(
                   unbound_resources,
                   std::unique_ptr<ResourceUtil>(std::move(util)), &tracker)
                   .ok());
}

TEST_F(ResourceTrackerTest, UnnormalizedTotalResources) {
  std::unique_ptr<ResourceUtil> util(
      new ResourceUtil({{{"cpu", 1}, {"gpu", 2}}}));
  std::unique_ptr<ResourceTracker> tracker;
  const auto unnormalized_resources = CreateProto<ResourceAllocation>(
      "resource_quantities { "
      "  resource { "
      "    device: 'cpu' "
      "    kind: 'ram' "
      "  } "
      "  quantity: 12 "
      "} ");
  TF_ASSERT_OK(ResourceTracker::Create(
      unnormalized_resources, std::unique_ptr<ResourceUtil>(std::move(util)),
      &tracker));
  // The total_resources proto should get normalized.
  EXPECT_THAT(tracker->total_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 12 "
                          "} "));
}

TEST_F(ResourceTrackerTest, RecomputeUsedResources) {
  // Verify the initial state.
  EXPECT_THAT(tracker_->used_resources(), EqualsProto(""));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));

  // Recompute used resources for {loader_0_, loader_1_, loader_3_}.
  TF_ASSERT_OK(tracker_->RecomputeUsedResources(
      {loader_0_.get(), loader_1_.get(), loader_3_.get()}));
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 6 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 10 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 12 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));

  // Recompute used resources for just {loader_0_}.
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_0_.get()}));
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 1 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 3 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, ReserveResourcesSuccessWithUsedResourcesBound) {
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_0_.get()}));
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 1 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 3 "
                          "} "));

  // If just loader_0_ is loaded, loader_2_ should also fit.
  bool success;
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_2_, &success));
  EXPECT_TRUE(success);
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 16 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 3 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, ReserveResourcesFailureWithUsedResourcesBound) {
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_1_.get()}));
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 5 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 7 "
                          "} "));

  // If loader_1_ is loaded, there isn't room for loader_2_.
  bool success;
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_2_, &success));
  EXPECT_FALSE(success);
  // The used resources should remain unchanged (i.e. only reflect loader_1_).
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 5 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 7 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, ReserveResourcesSuccessWithUsedResourcesUnbound) {
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_3_.get()}));
  EXPECT_THAT(tracker_->used_resources(), EqualsProto("resource_quantities { "
                                                      "  resource { "
                                                      "    device: 'gpu' "
                                                      "    kind: 'ram' "
                                                      "  } "
                                                      "  quantity: 12 "
                                                      "} "));

  // If just loader_3_ is loaded, loader_0_ should also fit.
  bool success;
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_0_, &success));
  EXPECT_TRUE(success);
  EXPECT_THAT(tracker_->used_resources(),
              EqualsProto("resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 12 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'cpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 1 "
                          "} "
                          "resource_quantities { "
                          "  resource { "
                          "    device: 'gpu' "
                          "    device_instance { value: 0 } "
                          "    kind: 'ram' "
                          "  } "
                          "  quantity: 3 "
                          "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, ReserveResourcesFailureWithUsedResourcesUnbound) {
  TF_ASSERT_OK(tracker_->RecomputeUsedResources({loader_3_.get()}));
  EXPECT_THAT(tracker_->used_resources(), EqualsProto("resource_quantities { "
                                                      "  resource { "
                                                      "    device: 'gpu' "
                                                      "    kind: 'ram' "
                                                      "  } "
                                                      "  quantity: 12 "
                                                      "} "));

  // If loader_3_ is loaded, there isn't room for loader_1_, or for another
  // copy of loader_3_.
  bool success;
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_1_, &success));
  EXPECT_FALSE(success);
  TF_ASSERT_OK(tracker_->ReserveResources(*loader_3_, &success));
  EXPECT_FALSE(success);
  // The used resources should remain unchanged (i.e. only reflect a single copy
  // of loader_3_).
  EXPECT_THAT(tracker_->used_resources(), EqualsProto("resource_quantities { "
                                                      "  resource { "
                                                      "    device: 'gpu' "
                                                      "    kind: 'ram' "
                                                      "  } "
                                                      "  quantity: 12 "
                                                      "} "));
  EXPECT_THAT(tracker_->total_resources(), EqualsProto(total_resources_));
}

TEST_F(ResourceTrackerTest, InvalidResourceEstimate) {
  bool success;
  EXPECT_FALSE(
      tracker_->ReserveResources(*invalid_resources_loader_, &success).ok());
  EXPECT_FALSE(tracker_
                   ->RecomputeUsedResources(
                       {loader_0_.get(), invalid_resources_loader_.get()})
                   .ok());
}

}  // namespace
}  // namespace serving
}  // namespace tensorflow
<|endoftext|>


<commit_before>#include "PagerWidget.h"
#include <blackbox/BlackBox.h>
#include <blackbox/gfx/utils_imgui.h>
#include <bblib/codecvt.h>
#include <imgui/imgui_internal.h>
#include <blackbox/utils_window.h>

namespace bb {

	PagerWidget::PagerWidget (WidgetConfig & cfg)
		: GuiWidget(cfg)
	{
		m_tasks.reserve(64);
	}

	void PagerWidget::UpdateTasks ()
	{
		m_tasks.clear();

		Tasks & tasks = BlackBox::Instance().GetTasks();
		tasks.MkDataCopy(m_tasks);
	}

	void resizeWindowToContents (HWND hwnd, int x, int y, int maxx, int maxy, int rnd)
	{
		if (x > maxx && y > maxy)
		{
			RECT r;
			GetWindowRect(hwnd, &r);
			int Width = r.left = r.right;
			int Height = r.bottom - r.top;

			DWORD dwStyle = ::GetWindowLongPtr(hwnd, GWL_STYLE);
			DWORD dwExStyle = ::GetWindowLongPtr(hwnd, GWL_EXSTYLE);

			RECT rc = { 0, 0, x, y };
			//::AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);

			destroyRoundedRect(hwnd);
			::SetWindowPos(hwnd, NULL, 0, 0, rc.right + 24, rc.bottom, SWP_NOZORDER | SWP_NOMOVE);
			createRoundedRect(hwnd, rc.right + 24, rc.bottom, rnd, rnd);
		}
	}

	void PagerWidget::DrawUI ()
	{
		ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiSetCond_Always);

		ImVec2 const & display = ImGui::GetIO().DisplaySize;

		if (m_contentSize.x > 0 && m_contentSize.y > 0)
		{
			ImGuiStyle & style = ImGui::GetStyle();
			resizeWindowToContents(m_hwnd, m_contentSize.x, m_contentSize.y, style.WindowMinSize.x, style.WindowMinSize.y, style.WindowRounding);
		}

		char name[256];
		codecvt_utf16_utf8(GetNameW(), name, 256);
		ImGui::Begin(name, &m_config.m_show, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize);

		WorkSpaces const & ws = BlackBox::Instance().GetWorkSpaces();

		UpdateTasks();

		bbstring const & cluster_id = ws.GetCurrentClusterId();
		if (WorkGraphConfig const * wg = ws.FindCluster(cluster_id))
		{
			char curr_ws_u8[TaskInfo::e_wspaceLenMax];
			codecvt_utf16_utf8(wg->m_currentVertexId, curr_ws_u8, TaskInfo::e_wspaceLenMax);

			ImGui::Text("%s %s", cluster_id.c_str(), curr_ws_u8);

			uint32_t const rows = wg->MaxRowCount();
			uint32_t const cols = wg->MaxColCount();

			if (cols && rows)
			{
				ImGui::Columns(cols, "mixed", true);
				ImGui::Separator();

				for (uint32_t c = 0; c < cols; ++c)
				{
					for (uint32_t r = 0; r < rows; ++r)
					{
						bbstring const & vertex_id = wg->m_vertexlists[r][c];
						char idu8[TaskInfo::e_wspaceLenMax];
						codecvt_utf16_utf8(vertex_id, idu8, TaskInfo::e_wspaceLenMax);

						if (ImGui::Button(idu8))
						{
							BlackBox::Instance().WorkSpacesSetCurrentVertexId(vertex_id);
						}

						int tmp = 0;
						for (TaskInfo & t : m_tasks)
						{
	// 						if (t.m_config && t.m_config->m_bbtasks)
	// 							continue;
							if (t.m_wspace == vertex_id)
							{
								if (tmp++ % 3 != 0)
									ImGui::SameLine();

								Tasks & tasks = BlackBox::Instance().GetTasks();
								IconId const icoid = t.m_icoSmall;
								if (!icoid.IsValid())
								{
									// @TODO: assign color to hwnd?
									if (ImGui::ColorButton(ImColor(0, 0, 128, 255)))
									{
										tasks.Focus(t.m_hwnd);
									}
								}
								else
								{
									int framing = -1;
									ImGui::PushID(t.m_hwnd);
									bool const clkd = ImGui::IconButton(icoid, ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128), framing);
									if (ImGui::BeginPopupContextItem(""))
									{
										bool is_sticky = t.m_config && t.m_config->m_sticky;
										if (ImGui::Selectable(is_sticky ? "UnStick" : "Stick"))
										{
											if (is_sticky)
												tasks.UnsetSticky(t.m_hwnd);
											else
												tasks.SetSticky(t.m_hwnd);
										}

										bool skip_taskman = t.m_config && t.m_config->m_taskman == false;
										if (ImGui::Selectable(skip_taskman ? "back to TaskMan" : "rm from TaskMan"))
										{
											if (skip_taskman)
												tasks.UnsetTaskManIgnored(t.m_hwnd);
											else
												tasks.SetTaskManIgnored(t.m_hwnd);
										}

										if (ImGui::Button("Close Menu"))
											ImGui::CloseCurrentPopup();
										ImGui::EndPopup();
									}
									if (clkd)
									{
										tasks.Focus(t.m_hwnd);
									}
									ImGui::PopID();
								}
							}
						}
					}
					ImGui::NextColumn();
				}
			}
		}
		ImGuiWindow * w = ImGui::GetCurrentWindowRead();
		ImVec2 const & sz1 = w->SizeContents;
		m_contentSize = sz1;
		ImGui::End();
 	}

}

<commit_msg>* pager: shade ignored windows<commit_after>#include "PagerWidget.h"
#include <blackbox/BlackBox.h>
#include <blackbox/gfx/utils_imgui.h>
#include <bblib/codecvt.h>
#include <imgui/imgui_internal.h>
#include <blackbox/utils_window.h>

namespace bb {

	PagerWidget::PagerWidget (WidgetConfig & cfg)
		: GuiWidget(cfg)
	{
		m_tasks.reserve(64);
	}

	void PagerWidget::UpdateTasks ()
	{
		m_tasks.clear();

		Tasks & tasks = BlackBox::Instance().GetTasks();
		tasks.MkDataCopy(m_tasks);
	}

	void resizeWindowToContents (HWND hwnd, int x, int y, int maxx, int maxy, int rnd)
	{
		if (x > maxx && y > maxy)
		{
			RECT r;
			GetWindowRect(hwnd, &r);
			int Width = r.left = r.right;
			int Height = r.bottom - r.top;

			DWORD dwStyle = ::GetWindowLongPtr(hwnd, GWL_STYLE);
			DWORD dwExStyle = ::GetWindowLongPtr(hwnd, GWL_EXSTYLE);

			RECT rc = { 0, 0, x, y };
			//::AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);

			destroyRoundedRect(hwnd);
			::SetWindowPos(hwnd, NULL, 0, 0, rc.right + 24, rc.bottom, SWP_NOZORDER | SWP_NOMOVE);
			createRoundedRect(hwnd, rc.right + 24, rc.bottom, rnd, rnd);
		}
	}

	void PagerWidget::DrawUI ()
	{
		ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiSetCond_Always);

		ImVec2 const & display = ImGui::GetIO().DisplaySize;

		if (m_contentSize.x > 0 && m_contentSize.y > 0)
		{
			ImGuiStyle & style = ImGui::GetStyle();
			resizeWindowToContents(m_hwnd, m_contentSize.x, m_contentSize.y, style.WindowMinSize.x, style.WindowMinSize.y, style.WindowRounding);
		}

		char name[256];
		codecvt_utf16_utf8(GetNameW(), name, 256);
		ImGui::Begin(name, &m_config.m_show, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize);

		WorkSpaces const & ws = BlackBox::Instance().GetWorkSpaces();

		UpdateTasks();

		bbstring const & cluster_id = ws.GetCurrentClusterId();
		if (WorkGraphConfig const * wg = ws.FindCluster(cluster_id))
		{
			char curr_ws_u8[TaskInfo::e_wspaceLenMax];
			codecvt_utf16_utf8(wg->m_currentVertexId, curr_ws_u8, TaskInfo::e_wspaceLenMax);

			ImGui::Text("%s %s", cluster_id.c_str(), curr_ws_u8);

			uint32_t const rows = wg->MaxRowCount();
			uint32_t const cols = wg->MaxColCount();

			if (cols && rows)
			{
				ImGui::Columns(cols, "mixed", true);
				ImGui::Separator();

				for (uint32_t c = 0; c < cols; ++c)
				{
					for (uint32_t r = 0; r < rows; ++r)
					{
						bbstring const & vertex_id = wg->m_vertexlists[r][c];
						char idu8[TaskInfo::e_wspaceLenMax];
						codecvt_utf16_utf8(vertex_id, idu8, TaskInfo::e_wspaceLenMax);

						if (ImGui::Button(idu8))
						{
							BlackBox::Instance().WorkSpacesSetCurrentVertexId(vertex_id);
						}

						int tmp = 0;
						for (TaskInfo & t : m_tasks)
						{
	// 						if (t.m_config && t.m_config->m_bbtasks)
	// 							continue;
							if (t.m_wspace == vertex_id)
							{
								if (tmp++ % 3 != 0)
									ImGui::SameLine();

								Tasks & tasks = BlackBox::Instance().GetTasks();
								IconId const icoid = t.m_icoSmall;
								if (!icoid.IsValid())
								{
									// @TODO: assign color to hwnd?
									if (ImGui::ColorButton(ImColor(0, 0, 128, 255)))
									{
										tasks.Focus(t.m_hwnd);
									}
								}
								else
								{
									int framing = -1;
									ImGui::PushID(t.m_hwnd);
									bool const skip_taskman = t.IsTaskManIgnored();
									bool const is_sticky = t.IsSticky();
									ImColor const col_int = ImColor(0, 0, 0, 0);
									ImColor const col_border = ImColor(255, 255, 255, 255);
									ImColor const col_int_skip_taskman = ImColor(0, 0, 0, 128);
									ImColor const col_border_skip = ImColor(0, 0, 0, 128);
									bool const clkd = ImGui::IconButton(icoid, skip_taskman ? col_int_skip_taskman : col_int, skip_taskman ? col_border_skip : col_border, framing);
									if (ImGui::BeginPopupContextItem(""))
									{
										if (ImGui::Selectable(is_sticky ? "UnStick" : "Stick"))
										{
											if (is_sticky)
												tasks.UnsetSticky(t.m_hwnd);
											else
												tasks.SetSticky(t.m_hwnd);
										}

										if (ImGui::Selectable(skip_taskman ? "back to TaskMan" : "rm from TaskMan"))
										{
											if (skip_taskman)
												tasks.UnsetTaskManIgnored(t.m_hwnd);
											else
												tasks.SetTaskManIgnored(t.m_hwnd);
										}

										if (ImGui::Button("Close Menu"))
											ImGui::CloseCurrentPopup();
										ImGui::EndPopup();
									}
									if (clkd)
									{
										tasks.Focus(t.m_hwnd);
									}
									ImGui::PopID();
								}
							}
						}
					}
					ImGui::NextColumn();
				}
			}
		}
		ImGuiWindow * w = ImGui::GetCurrentWindowRead();
		ImVec2 const & sz1 = w->SizeContents;
		m_contentSize = sz1;
		ImGui::End();
 	}

}

<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright David Doria 2012 daviddoria@gmail.com
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/

#ifndef InpaintingVisitor_HPP
#define InpaintingVisitor_HPP

#include "Visitors/InpaintingVisitorParent.h"

// Concepts
#include "Concepts/DescriptorVisitorConcept.hpp"

// Accept criteria
#include "ImageProcessing/BoundaryEnergy.h"

// Boost
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>

// Helpers
#include "ITKHelpers/ITKHelpers.h"
#include "BoostHelpers/BoostHelpers.h"

// Submodules
#include <ITKVTKHelpers/ITKVTKHelpers.h>

/**
 * This is a visitor that complies with the InpaintingVisitorConcept. It forwards
 * initialize_vertex and discover_vertex, the only two functions that need to know about
 * the descriptor type, to a visitor that models DescriptorVisitorConcept.
 * The visitor needs to know the patch size of the patch to be inpainted because it uses
 * this size to traverse the inpainted region to update the boundary.
 */
template <typename TGraph, typename TImage, typename TBoundaryNodeQueue,
          typename TDescriptorVisitor, typename TAcceptanceVisitor, typename TPriority,
          typename TPriorityMap, typename TBoundaryStatusMap>
class InpaintingVisitor : public InpaintingVisitorParent<TGraph>
{
  BOOST_CONCEPT_ASSERT((DescriptorVisitorConcept<TDescriptorVisitor, TGraph>));

  typedef typename boost::graph_traits<TGraph>::vertex_descriptor VertexDescriptorType;

  /** The image to inpaint. */
  TImage* Image;

  /** The mask indicating the region to inpaint. */
  Mask* MaskImage;

  /** A queue to use to determine which patch to inpaint next. */
  TBoundaryNodeQueue& BoundaryNodeQueue;

  /** A function to determine the priority of each target patch. */
  TPriority* PriorityFunction;

  /** A visitor to do patch descriptor specific operations. */
  TDescriptorVisitor& DescriptorVisitor;

  /** A visitor to perform specified actions when a match is accepted. */
  TAcceptanceVisitor& AcceptanceVisitor;

  /** A map indicating the priority of each pixel. */
  TPriorityMap& PriorityMap;

  /** A map indicating if each pixel is on the boundary or not. */
  TBoundaryStatusMap& BoundaryStatusMap;

  /** The radius of the patches to use to inpaint the image. */
  const unsigned int PatchHalfWidth;

  /** The name of the file to output the inpainted image. */
  std::string ResultFileName;

  /** How many patches have been finished so far. */
  unsigned int NumberOfFinishedPatches;

  /** As the image is inpainted, this flag determines if new source patches can be created from patches which are now valid. */
  bool AllowNewPatches;

  // Debug only
  /** A flag that determines if debug images should be written at each iteration. */
  bool DebugImages;

public:

  void SetDebugImages(const bool debugImages)
  {
    this->DebugImages = debugImages;
  }

  /** Constructor. Everything must be specified in this constructor. (There is no default constructor). */
  InpaintingVisitor(TImage* const image, Mask* const mask,
                    TBoundaryNodeQueue& boundaryNodeQueue,
                    TDescriptorVisitor& descriptorVisitor, TAcceptanceVisitor& acceptanceVisitor,
                    TPriorityMap& priorityMap, TPriority* const priorityFunction,
                    const unsigned int patchHalfWidth, TBoundaryStatusMap& boundaryStatusMap,
                    const std::string& resultFileName,
                    const std::string& visitorName = "InpaintingVisitor") :
    InpaintingVisitorParent<TGraph>(visitorName),
    Image(image), MaskImage(mask), BoundaryNodeQueue(boundaryNodeQueue), PriorityFunction(priorityFunction),
    DescriptorVisitor(descriptorVisitor), AcceptanceVisitor(acceptanceVisitor),
    PriorityMap(priorityMap), BoundaryStatusMap(boundaryStatusMap),
    PatchHalfWidth(patchHalfWidth), ResultFileName(resultFileName), NumberOfFinishedPatches(0), AllowNewPatches(false), DebugImages(false)
  {
  }

  void InitializeVertex(VertexDescriptorType v) const
  {
    this->DescriptorVisitor.InitializeVertex(v);
  }

  void DiscoverVertex(VertexDescriptorType v) const
  {
    this->DescriptorVisitor.DiscoverVertex(v);
  }

  void PotentialMatchMade(VertexDescriptorType target, VertexDescriptorType source)
  {
    std::cout << "InpaintingVisitor::PotentialMatchMade: target " << target[0] << " " << target[1]
              << " source: " << source[0] << " " << source[1] << std::endl;

    if(!this->MaskImage->IsValid(ITKHelpers::CreateIndex(source)))
    {
      std::stringstream ss;
      ss << "InpaintingVisitor::PotentialMatchMade: Potential source pixel " << source[0] << " " << source[1] << " is not valid in the mask!";
      throw std::runtime_error(ss.str());
    }

    //if(!this->MaskImage->HasHoleNeighborInRegion(ITKHelpers::CreateIndex(target), this->MaskImage->GetLargestPossibleRegion()))
    if(!this->MaskImage->HasHoleNeighbor(ITKHelpers::CreateIndex(target)))
    {
      std::stringstream ss;
      ss << "InpaintingVisitor::PotentialMatchMade: Potential target pixel " << target[0] << " " << target[1]
         << " does not have a hole neighbor (which means it is not on the boundary)!";
      throw std::runtime_error(ss.str());
    }
  }

  bool AcceptMatch(VertexDescriptorType target, VertexDescriptorType source) const
  {
    float energy = 0.0f;
    return AcceptanceVisitor.AcceptMatch(target, source, energy);
  }

  void FinishVertex(VertexDescriptorType targetNode, VertexDescriptorType sourceNode)// __attribute__((optimize(0)))
  {
    // Mark this pixel and the area around it as filled, and mark the mask in this region as filled.
    // Determine the new boundary, and setup the nodes in the boundary queue.

    std::cout << "InpaintingVisitor::FinishVertex()" << std::endl;

    // Construct the region around the vertex
    itk::Index<2> indexToFinish = ITKHelpers::CreateIndex(targetNode);

    itk::ImageRegion<2> regionToFinish = ITKHelpers::GetRegionInRadiusAroundPixel(indexToFinish, PatchHalfWidth);

    regionToFinish.Crop(this->Image->GetLargestPossibleRegion()); // Make sure the region is entirely inside the image
    // (because we allow target patches to not be entirely inside the image to handle the case where
    // the hole boundary is near the image boundary)

    // Update the priority function. This must be done BEFORE the mask is filled,
    // as the old mask is required in some of the Priority functors to determine where to update some things.
    this->PriorityFunction->Update(sourceNode, targetNode, this->NumberOfFinishedPatches);

    // Mark all the pixels in this region as filled in the mask.
    ITKHelpers::SetRegionToConstant(this->MaskImage, regionToFinish, this->MaskImage->GetValidValue());

    // Initialize all vertices in the newly filled region because they may now be valid source nodes.
    // (You may not want to do this in some cases (i.e. if the descriptors needed cannot be
    // computed on newly filled regions))

    if(this->AllowNewPatches)
    {
      itk::ImageRegionConstIteratorWithIndex<TImage> gridIterator(Image, regionToFinish);
      while(!gridIterator.IsAtEnd())
      {
        VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(gridIterator.GetIndex());

        InitializeVertex(v);
        ++gridIterator;
      }
    }

    // Add pixels that are on the new boundary to the queue, and mark other pixels as not in the queue.
    itk::ImageRegionConstIteratorWithIndex<Mask> imageIterator(this->MaskImage, regionToFinish);

    while(!imageIterator.IsAtEnd())
    {
      VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(imageIterator.GetIndex());

      // This makes them ignored if they are still in the boundaryNodeQueue.
      //if(this->MaskImage->HasHoleNeighborInRegion(imageIterator.GetIndex(), this->MaskImage->GetLargestPossibleRegion()))
      if(this->MaskImage->HasHoleNeighbor(imageIterator.GetIndex()))
      {
        // Note: must set the value in the priority map before pushing the node
        // into the queue (as the priority is what
        // determines the node's position in the queue).
        float priority = this->PriorityFunction->ComputePriority(imageIterator.GetIndex());
        //std::cout << "updated priority: " << priority << std::endl;
        put(this->PriorityMap, v, priority);

        put(this->BoundaryStatusMap, v, true);
        this->BoundaryNodeQueue.push(v);
      }
      else
      {
        put(this->BoundaryStatusMap, v, false);
      }

      ++imageIterator;
    }

    // std::cout << "FinishVertex after traversing finishing region there are "
    //           << BoostHelpers::CountValidQueueNodes(BoundaryNodeQueue, BoundaryStatusMap)
    //           << " valid nodes in the queue." << std::endl;

    // Sometimes pixels that are not in the finishing region that were boundary pixels are no longer
    // boundary pixels after the filling. Check for these.

    // Expand the region
    itk::ImageRegion<2> expandedRegion = ITKHelpers::GetRegionInRadiusAroundPixel(indexToFinish, PatchHalfWidth + 1);
    expandedRegion.Crop(this->Image->GetLargestPossibleRegion()); // Make sure the region is entirely inside the image (to allow for target regions near the image boundary)
    std::vector<itk::Index<2> > boundaryPixels = ITKHelpers::GetBoundaryPixels(expandedRegion);
    for(unsigned int i = 0; i < boundaryPixels.size(); ++i)
    {
      if(!this->MaskImage->HasHoleNeighbor(boundaryPixels[i])) // the region (the entire image) can be omitted, as this function automatically checks if the pixels are inside the image
      {
        VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(boundaryPixels[i]);
        put(this->BoundaryStatusMap, v, false);
      }
    }

    // std::cout << "FinishVertex after removing stale nodes outside finishing region there are "
    //               << BoostHelpers::CountValidQueueNodes(BoundaryNodeQueue, BoundaryStatusMap)
    //               << " valid nodes in the queue." << std::endl;

    this->NumberOfFinishedPatches++;

    std::cout << "Leave InpaintingVisitor::FinishVertex()" << std::endl;
  } // end FinishVertex

  void InpaintingComplete() const
  {
    std::cout << "Inpainting complete!" << std::endl;
    // We prefer to write the final image in the calling function, as there we will know what type it is (i.e. do we need to convert back to RGB? etc.)
  }

}; // end InpaintingVisitor

#endif
<commit_msg>Add an ASCII example of how a boundary pixel can get stranded.<commit_after>/*=========================================================================
 *
 *  Copyright David Doria 2012 daviddoria@gmail.com
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/

#ifndef InpaintingVisitor_HPP
#define InpaintingVisitor_HPP

#include "Visitors/InpaintingVisitorParent.h"

// Concepts
#include "Concepts/DescriptorVisitorConcept.hpp"

// Accept criteria
#include "ImageProcessing/BoundaryEnergy.h"

// Boost
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>

// Helpers
#include "ITKHelpers/ITKHelpers.h"
#include "BoostHelpers/BoostHelpers.h"

// Submodules
#include <ITKVTKHelpers/ITKVTKHelpers.h>

/**
 * This is a visitor that complies with the InpaintingVisitorConcept. It forwards
 * initialize_vertex and discover_vertex, the only two functions that need to know about
 * the descriptor type, to a visitor that models DescriptorVisitorConcept.
 * The visitor needs to know the patch size of the patch to be inpainted because it uses
 * this size to traverse the inpainted region to update the boundary.
 */
template <typename TGraph, typename TImage, typename TBoundaryNodeQueue,
          typename TDescriptorVisitor, typename TAcceptanceVisitor, typename TPriority,
          typename TPriorityMap, typename TBoundaryStatusMap>
class InpaintingVisitor : public InpaintingVisitorParent<TGraph>
{
  BOOST_CONCEPT_ASSERT((DescriptorVisitorConcept<TDescriptorVisitor, TGraph>));

  typedef typename boost::graph_traits<TGraph>::vertex_descriptor VertexDescriptorType;

  /** The image to inpaint. */
  TImage* Image;

  /** The mask indicating the region to inpaint. */
  Mask* MaskImage;

  /** A queue to use to determine which patch to inpaint next. */
  TBoundaryNodeQueue& BoundaryNodeQueue;

  /** A function to determine the priority of each target patch. */
  TPriority* PriorityFunction;

  /** A visitor to do patch descriptor specific operations. */
  TDescriptorVisitor& DescriptorVisitor;

  /** A visitor to perform specified actions when a match is accepted. */
  TAcceptanceVisitor& AcceptanceVisitor;

  /** A map indicating the priority of each pixel. */
  TPriorityMap& PriorityMap;

  /** A map indicating if each pixel is on the boundary or not. */
  TBoundaryStatusMap& BoundaryStatusMap;

  /** The radius of the patches to use to inpaint the image. */
  const unsigned int PatchHalfWidth;

  /** The name of the file to output the inpainted image. */
  std::string ResultFileName;

  /** How many patches have been finished so far. */
  unsigned int NumberOfFinishedPatches;

  /** As the image is inpainted, this flag determines if new source patches can be created from patches which are now valid. */
  bool AllowNewPatches;

  // Debug only
  /** A flag that determines if debug images should be written at each iteration. */
  bool DebugImages;

public:

  void SetDebugImages(const bool debugImages)
  {
    this->DebugImages = debugImages;
  }

  /** Constructor. Everything must be specified in this constructor. (There is no default constructor). */
  InpaintingVisitor(TImage* const image, Mask* const mask,
                    TBoundaryNodeQueue& boundaryNodeQueue,
                    TDescriptorVisitor& descriptorVisitor, TAcceptanceVisitor& acceptanceVisitor,
                    TPriorityMap& priorityMap, TPriority* const priorityFunction,
                    const unsigned int patchHalfWidth, TBoundaryStatusMap& boundaryStatusMap,
                    const std::string& resultFileName,
                    const std::string& visitorName = "InpaintingVisitor") :
    InpaintingVisitorParent<TGraph>(visitorName),
    Image(image), MaskImage(mask), BoundaryNodeQueue(boundaryNodeQueue), PriorityFunction(priorityFunction),
    DescriptorVisitor(descriptorVisitor), AcceptanceVisitor(acceptanceVisitor),
    PriorityMap(priorityMap), BoundaryStatusMap(boundaryStatusMap),
    PatchHalfWidth(patchHalfWidth), ResultFileName(resultFileName), NumberOfFinishedPatches(0), AllowNewPatches(false), DebugImages(false)
  {
  }

  void InitializeVertex(VertexDescriptorType v) const
  {
    this->DescriptorVisitor.InitializeVertex(v);
  }

  void DiscoverVertex(VertexDescriptorType v) const
  {
    this->DescriptorVisitor.DiscoverVertex(v);
  }

  void PotentialMatchMade(VertexDescriptorType target, VertexDescriptorType source)
  {
    std::cout << "InpaintingVisitor::PotentialMatchMade: target " << target[0] << " " << target[1]
              << " source: " << source[0] << " " << source[1] << std::endl;

    if(!this->MaskImage->IsValid(ITKHelpers::CreateIndex(source)))
    {
      std::stringstream ss;
      ss << "InpaintingVisitor::PotentialMatchMade: Potential source pixel " << source[0] << " " << source[1] << " is not valid in the mask!";
      throw std::runtime_error(ss.str());
    }

    //if(!this->MaskImage->HasHoleNeighborInRegion(ITKHelpers::CreateIndex(target), this->MaskImage->GetLargestPossibleRegion()))
    if(!this->MaskImage->HasHoleNeighbor(ITKHelpers::CreateIndex(target)))
    {
      std::stringstream ss;
      ss << "InpaintingVisitor::PotentialMatchMade: Potential target pixel " << target[0] << " " << target[1]
         << " does not have a hole neighbor (which means it is not on the boundary)!";
      throw std::runtime_error(ss.str());
    }
  }

  bool AcceptMatch(VertexDescriptorType target, VertexDescriptorType source) const
  {
    float energy = 0.0f;
    return AcceptanceVisitor.AcceptMatch(target, source, energy);
  }

  void FinishVertex(VertexDescriptorType targetNode, VertexDescriptorType sourceNode)// __attribute__((optimize(0)))
  {
    // Mark this pixel and the area around it as filled, and mark the mask in this region as filled.
    // Determine the new boundary, and setup the nodes in the boundary queue.

    std::cout << "InpaintingVisitor::FinishVertex()" << std::endl;

    // Construct the region around the vertex
    itk::Index<2> indexToFinish = ITKHelpers::CreateIndex(targetNode);

    itk::ImageRegion<2> regionToFinish = ITKHelpers::GetRegionInRadiusAroundPixel(indexToFinish, PatchHalfWidth);

    // Make sure the region is entirely inside the image
    // (because we allow target patches to not be entirely inside the image to handle the case where
    // the hole boundary is near the image boundary)
    regionToFinish.Crop(this->Image->GetLargestPossibleRegion());

    // Update the priority function. This must be done BEFORE the mask is filled,
    // as the old mask is required in some of the Priority functors to determine where to update some things.
    this->PriorityFunction->Update(sourceNode, targetNode, this->NumberOfFinishedPatches);

    // Mark all the pixels in this region as filled in the mask.
    ITKHelpers::SetRegionToConstant(this->MaskImage, regionToFinish, this->MaskImage->GetValidValue());

    // Initialize all vertices in the newly filled region because they may now be valid source nodes.
    // (You may not want to do this in some cases (i.e. if the descriptors needed cannot be
    // computed on newly filled regions))

    if(this->AllowNewPatches)
    {
      itk::ImageRegionConstIteratorWithIndex<TImage> gridIterator(Image, regionToFinish);
      while(!gridIterator.IsAtEnd())
      {
        VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(gridIterator.GetIndex());

        InitializeVertex(v);
        ++gridIterator;
      }
    }

    // Add pixels that are on the new boundary to the queue, and mark other pixels as not in the queue.
    itk::ImageRegionConstIteratorWithIndex<Mask> imageIterator(this->MaskImage, regionToFinish);

    while(!imageIterator.IsAtEnd())
    {
      VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(imageIterator.GetIndex());

      // This makes them ignored if they are still in the boundaryNodeQueue.
      //if(this->MaskImage->HasHoleNeighborInRegion(imageIterator.GetIndex(), this->MaskImage->GetLargestPossibleRegion()))
      if(this->MaskImage->HasHoleNeighbor(imageIterator.GetIndex()))
      {
        // Note: must set the value in the priority map before pushing the node
        // into the queue (as the priority is what
        // determines the node's position in the queue).
        float priority = this->PriorityFunction->ComputePriority(imageIterator.GetIndex());
        //std::cout << "updated priority: " << priority << std::endl;
        put(this->PriorityMap, v, priority);

        put(this->BoundaryStatusMap, v, true);
        this->BoundaryNodeQueue.push(v);
      }
      else
      {
        put(this->BoundaryStatusMap, v, false);
      }

      ++imageIterator;
    }

    // std::cout << "FinishVertex after traversing finishing region there are "
    //           << BoostHelpers::CountValidQueueNodes(BoundaryNodeQueue, BoundaryStatusMap)
    //           << " valid nodes in the queue." << std::endl;

    // Sometimes pixels that are not in the finishing region that were boundary pixels are no longer
    // boundary pixels after the filling. Check for these.
    // E.g. (H=hole, B=boundary, V=valid, Q=query, F=filled, N=new boundary,
    // R=old boundary pixel that needs to be removed because it is no longer on the boundary)
    // Before filling

    /* V V V B H H H H
     * V V V B H H H H
     * V V V B H H H H
     * V V V B B Q B B
     * V V V V V V V V
     */
    // After filling

    /* V V V B H H H H
     * V V V B H H H H
     * V V V B F F F H
     * V V V B F F F B
     * V V V V F F F V
     */
    // New boundary
    /* V V V B H H H H
     * V V V B H H H H
     * V V V B N N N H
     * V V V R F F N B
     * V V V V F F F V
     */

    // Expand the region
    itk::ImageRegion<2> expandedRegion = ITKHelpers::GetRegionInRadiusAroundPixel(indexToFinish, PatchHalfWidth + 1);
    expandedRegion.Crop(this->Image->GetLargestPossibleRegion()); // Make sure the region is entirely inside the image (to allow for target regions near the image boundary)
    std::vector<itk::Index<2> > boundaryPixels = ITKHelpers::GetBoundaryPixels(expandedRegion);
    for(unsigned int i = 0; i < boundaryPixels.size(); ++i)
    {
      if(!this->MaskImage->HasHoleNeighbor(boundaryPixels[i])) // the region (the entire image) can be omitted, as this function automatically checks if the pixels are inside the image
      {
        VertexDescriptorType v = Helpers::ConvertFrom<VertexDescriptorType, itk::Index<2> >(boundaryPixels[i]);
        put(this->BoundaryStatusMap, v, false);
      }
    }

    // std::cout << "FinishVertex after removing stale nodes outside finishing region there are "
    //               << BoostHelpers::CountValidQueueNodes(BoundaryNodeQueue, BoundaryStatusMap)
    //               << " valid nodes in the queue." << std::endl;

    this->NumberOfFinishedPatches++;

    std::cout << "Leave InpaintingVisitor::FinishVertex()" << std::endl;
  } // end FinishVertex

  void InpaintingComplete() const
  {
    std::cout << "Inpainting complete!" << std::endl;
    // We prefer to write the final image in the calling function, as there we will know what type it is (i.e. do we need to convert back to RGB? etc.)
  }

}; // end InpaintingVisitor

#endif
<|endoftext|>


<commit_before>#include <isl/set.h>
#include <isl/union_map.h>
#include <isl/union_set.h>
#include <isl/ast_build.h>
#include <isl/schedule.h>
#include <isl/schedule_node.h>

#include <tiramisu/debug.h>
#include <tiramisu/core.h>

#include <string.h>
#include <Halide.h>

/**
  The goal of this tutorial is to implement in Tiramisu a code that is
  equivalent to the following

  for (int i = 0; i < 10; i++)
    for (int j = 0; j < 20; j++)
      output[i, j] = input[i, j] + i + 2;
*/

#define NN 10
#define MM 20

using namespace tiramisu;

int main(int argc, char **argv)
{
    // Set default tiramisu options.
    global::set_default_tiramisu_options();

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------

    // Declare the function tut_02.
    function tut_02("tut_02");

    constant N_const("N", expr((int32_t) NN), p_int32, true, NULL, 0, &tut_02);
    constant M_const("M", expr((int32_t) MM), p_int32, true, NULL, 0, &tut_02);

    // Declare variables
    var i("i"), j("j");

    // Declare a wrapper around the input.
    computation input("[N, M]->{input[i,j]: 0<=i<N and 0<=j<M}", expr(), false, p_uint8, &tut_02);

    // Declare expression and output computation.
    expr e = input(i, j) + cast(p_uint8, i)+ (uint8_t)4;
    computation output("[N, M]->{output[i,j]: 0<=i<N and 0<=j<M}", e, true, p_uint8, &tut_02);

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    // Set the schedule of the computation.
    var i0("i0"), i1("i1"), j0("j0"), j1("j1");
    output.tile(i, j, 2, 2, i0, j0, i1, j1);
    output.tag_parallel_level(i0);

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------

    buffer b_input("b_input", {expr(NN), expr(MM)}, p_uint8, a_input, &tut_02);
    buffer b_output("b_output", {expr(NN), expr(MM)}, p_uint8, a_output, &tut_02);

    // Map the computations to a buffer.
    input.set_access("{input[i,j]->b_input[i,j]}");
    output.set_access("{output[i,j]->b_output[i,j]}");

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------

    // Set the arguments to tut_02
    tut_02.set_arguments({&b_input, &b_output});
    // Generate code
    tut_02.gen_time_space_domain();
    tut_02.gen_isl_ast();
    tut_02.gen_halide_stmt();
    tut_02.gen_halide_obj("build/generated_fct_developers_tutorial_02.o");

    // Some debugging
    tut_02.dump_iteration_domain();
    tut_02.dump_halide_stmt();

    // Dump all the fields of the tut_02 class.
    tut_02.dump(true);

    return 0;
}
/**
 * Current limitations:
 * - Note that the type of the invariants N and M are "int32_t". This is
 *   important because these invariants are used later as loop bounds and the
 *   type of the bounds and the iterators should be the same for correct code
 *   generation. This implies that the invariants should be of type "int32_t".
 */
<commit_msg>update developer tuto_02<commit_after>#include <tiramisu/tiramisu.h>

/**
  The goal of this tutorial is to implement in Tiramisu a code that is
  equivalent to the following

  for (int i = 0; i < 10; i++)
    for (int j = 0; j < 20; j++)
      output[i, j] = input[i, j] + i + 2;
*/

#define NN 10
#define MM 20

using namespace tiramisu;

int main(int argc, char **argv)
{
    // Set default tiramisu options.
    global::set_default_tiramisu_options();

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------

    // Declare the function tut_02.
    function tut_02("tut_02");

    constant N_const("N", expr((int32_t) NN), p_int32, true, NULL, 0, &tut_02);
    constant M_const("M", expr((int32_t) MM), p_int32, true, NULL, 0, &tut_02);

    // Declare variables
    var i("i"), j("j");

    // Declare a wrapper around the input.
    computation input("[N, M]->{input[i,j]: 0<=i<N and 0<=j<M}", expr(), false, p_uint8, &tut_02);

    // Declare expression and output computation.
    expr e = input(i, j) + cast(p_uint8, i)+ (uint8_t)4;
    computation output("[N, M]->{output[i,j]: 0<=i<N and 0<=j<M}", e, true, p_uint8, &tut_02);

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    // Set the schedule of the computation.
    var i0("i0"), i1("i1"), j0("j0"), j1("j1");
    output.tile(i, j, 2, 2, i0, j0, i1, j1);
    output.tag_parallel_level(i0);

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------

    buffer b_input("b_input", {expr(NN), expr(MM)}, p_uint8, a_input, &tut_02);
    buffer b_output("b_output", {expr(NN), expr(MM)}, p_uint8, a_output, &tut_02);

    // Map the computations to a buffer.
    input.set_access("{input[i,j]->b_input[i,j]}");
    output.set_access("{output[i,j]->b_output[i,j]}");

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------

    // Set the arguments to tut_02
    tut_02.set_arguments({&b_input, &b_output});
    // Generate code
    tut_02.gen_time_space_domain();
    tut_02.gen_isl_ast();
    tut_02.gen_halide_stmt();
    tut_02.gen_halide_obj("build/generated_fct_developers_tutorial_02.o");

    // Some debugging
    tut_02.dump_iteration_domain();
    tut_02.dump_halide_stmt();

    // Dump all the fields of the tut_02 class.
    tut_02.dump(true);

    return 0;
}
/**
 * Current limitations:
 * - Note that the type of the invariants N and M are "int32_t". This is
 *   important because these invariants are used later as loop bounds and the
 *   type of the bounds and the iterators should be the same for correct code
 *   generation. This implies that the invariants should be of type "int32_t".
 */
<|endoftext|>


<commit_before>#include "ride/runner.h"
#include <wx/utils.h>
#include <wx/process.h>
#include <wx/txtstrm.h>

#include "ride/mainwindow.h"

class PipedProcess;
class Process;

const int RUNNER_CONSOLE_OPTION = wxEXEC_HIDE_CONSOLE;
// const int RUNNER_CONSOLE_OPTION = wxEXEC_SHOW_CONSOLE;

//////////////////////////////////////////////////////////////////////////

Command::Command(const wxString& r, const wxString& c) : root(r), cmd(c) {
}

//////////////////////////////////////////////////////////////////////////

// idle timer to keep the process updated since wx apperently doesn't do that
class IdleTimer : public wxTimer {
public:
  IdleTimer(SingleRunner::Pimpl* p) : pimpl_(p) {
  }
  void Notify();

  SingleRunner::Pimpl* pimpl_;
};

//////////////////////////////////////////////////////////////////////////

struct SingleRunner::Pimpl {
  explicit Pimpl(SingleRunner* p) : parent_(p), processes_(NULL), delete_processes_(NULL), pid_(0), has_exit_code_(false), exit_code_(-1) {
    assert(parent_);
    idle_timer_.reset(new IdleTimer(this));
  }
  ~Pimpl();

  void Append(const wxString& s) {
    parent_->Append(s);
  }

  void MarkForDeletion(Process *process);

  bool RunCmd(const Command& cmd);

  void Notify();

  void OnCompleted() {
    assert(parent_);
    parent_->Completed();
    idle_timer_->Stop();
  }

  SingleRunner* parent_;
  Process* processes_; // the current running process or NULL
  Process* delete_processes_; // process to be deleted at the end
  long pid_; // the id of the current or previous running process
  std::unique_ptr<IdleTimer> idle_timer_;

  int exit_code() const {
    assert(has_exit_code_);
    return exit_code_;
  }
  bool has_exit_code() const {
    return has_exit_code_;
  }
  void set_exit_code(int x) {
    exit_code_ = x;
    has_exit_code_ = true;
  }

private:
  bool has_exit_code_;
  int exit_code_;
};

void IdleTimer::Notify() {
  pimpl_->Notify();
}

class Process : public wxProcess
{
public:
  Process(SingleRunner::Pimpl* project, const wxString& cmd)
    : wxProcess(wxPROCESS_DEFAULT), cmd_(cmd), null_members_called_(false)
  {
    runner_ = project;
    Redirect();
  }

  virtual void OnTerminate(int pid, int status) {
    if (runner_) {
      assert(runner_->pid_ == pid);

      // show the rest of the output
      while (HasInput()) {}
      runner_->MarkForDeletion(this);

      runner_->Append(wxString::Format(wxT("Process %u ('%s') terminated with exit code %d."),
        pid, cmd_.c_str(), status));
      runner_->Append("");
      runner_->set_exit_code(status);
      runner_->OnCompleted();
    }
    else {
      // if we are here that should mean we have called have called NullMember()
      // That should mean that we are done with the object and we
      // can delete this here, *fingers crossed*
      assert(null_members_called_);
      delete this;
    }
  }

  virtual bool HasInput() {
    // original source: http://sourceforge.net/p/fourpane/code/HEAD/tree/trunk/ExecuteInDialog.cpp

    // The original used wxTextInputStream to read a line at a time.  Fine, except when there was no \n, whereupon the thing would hang
    // Instead, read the stream (which may occasionally contain non-ascii bytes e.g. from g++) into a memorybuffer, then to a wxString

    bool hasInput = false;

    while (IsInputAvailable()) {
      wxMemoryBuffer buf;
      do {
        const char c = GetInputStream()->GetC();

        if (GetInputStream()->Eof()) break;
        if (c == wxT('\n')) break;
        buf.AppendByte(c);
      } while (IsInputAvailable());

      wxString line((const char*)buf.GetData(), wxConvUTF8, buf.GetDataLen()); // Convert the line to utf8
      runner_->Append(line);
      hasInput = true;
    }

    while (IsErrorAvailable())
    {
      wxMemoryBuffer buf;
      do
      {
        const char c = GetErrorStream()->GetC();

        if (GetErrorStream()->Eof()) break;
        if (c == wxT('\n')) break;
        buf.AppendByte(c);
      } while (IsErrorAvailable());

      wxString line((const char*)buf.GetData(), wxConvUTF8, buf.GetDataLen());
      runner_->Append(line);
      hasInput = true;
    }

    return hasInput;
  }

  void NullMembers() {
    runner_ = NULL;
    null_members_called_ = true;
  }

protected:
  SingleRunner::Pimpl *runner_;
  wxString cmd_;
  bool null_members_called_;
};

void SingleRunner::Pimpl::Notify(){
  if (processes_) {
    // sometimes the output hangs until we close the window
    // seems to be waiting for output or something
    // getting the input in a callback seems to remove the waiting...
    processes_->HasInput();
  }
}

bool SingleRunner::Pimpl::RunCmd(const Command& c) {
  Process* process = new Process(this, c.cmd);
  Append("> " + c.cmd);

  wxExecuteEnv env;
  env.cwd = c.root;

  const int flags = wxEXEC_ASYNC | RUNNER_CONSOLE_OPTION;

  const long process_id = wxExecute(c.cmd, flags, process, &env);

  // async call
  if (!process_id) {
    Append(wxT("Execution failed."));
    delete process;
    return false;
  }

  assert(processes_ == NULL);
  assert(pid_ == 0);
  processes_ = process;
  pid_ = process_id;

  idle_timer_->Start(100);
  return true;
}

void SingleRunner::Pimpl::MarkForDeletion(Process *process)
{
  assert(processes_ == process);
  processes_ = NULL;
  delete_processes_ = process;
}

SingleRunner::Pimpl:: ~Pimpl() {
  if (processes_ ) processes_->NullMembers();
  if (delete_processes_) delete_processes_->NullMembers();
  delete delete_processes_;
}

//////////////////////////////////////////////////////////////////////////

SingleRunner::SingleRunner() : pimpl(new Pimpl(this)) {
}

SingleRunner::~SingleRunner() {
}

bool SingleRunner::RunCmd(const Command& cmd) {
  assert(pimpl);
  assert(this->IsRunning() == false);
  return pimpl->RunCmd(cmd);
}

bool SingleRunner::IsRunning() const {
  const bool has_process = pimpl->processes_ != NULL;
  if (has_process == false) return false;
  const bool exists = wxProcess::Exists(pimpl->processes_->GetPid());
  pimpl->processes_->HasInput();
  return !pimpl->has_exit_code();
}

void SingleRunner::Completed() {
  // empty
}

int SingleRunner::GetExitCode() {
  assert(this->IsRunning() == false);
  assert(pimpl->pid_ != 0);
  return pimpl->exit_code();
}

//////////////////////////////////////////////////////////////////////////

class MultiRunner::Runner : public SingleRunner {
public:
  Runner(MultiRunner* r) : runner_(r) {
    assert(runner_);
  }

  virtual void Append(const wxString& str) {
    assert(runner_);
    runner_->Append(str);
  }
  virtual void Completed() {
    assert(runner_);
    runner_->RunNext(GetExitCode());
  }
  bool Run(const Command& cmd) {
    return RunCmd(cmd);
  }
private:
  MultiRunner* runner_;
};

MultiRunner::MultiRunner(){
}

MultiRunner::~MultiRunner(){
}

bool MultiRunner::RunCmd(const Command& cmd) {
  commands_.push_back(cmd);
  if (IsRunning() == true) return true;
  return RunNext(0);
}

bool MultiRunner::RunNext(int last_exit_code) {
  assert(IsRunning() == false);
  if (commands_.empty()) return false;

  if (last_exit_code == 0) {
    last_runner_ = runner_;
    runner_.reset(new Runner(this));
    const bool run_result = runner_->Run(*commands_.begin());
    if (run_result) {
      commands_.erase(commands_.begin());
    }
    return run_result;
  }
  else {
    commands_.clear();
    return false;
  }
}

bool MultiRunner::IsRunning() const {
  if (runner_) {
    return runner_->IsRunning();
  }
  return false;
}
<commit_msg>started on simplifying the runner implementation<commit_after>#include "ride/runner.h"
#include <wx/utils.h>
#include <wx/process.h>
#include <wx/txtstrm.h>

#include "ride/mainwindow.h"

class PipedProcess;
class Process;

const int RUNNER_CONSOLE_OPTION = wxEXEC_HIDE_CONSOLE;
// const int RUNNER_CONSOLE_OPTION = wxEXEC_SHOW_CONSOLE;

//////////////////////////////////////////////////////////////////////////

Command::Command(const wxString& r, const wxString& c) : root(r), cmd(c) {
}

//////////////////////////////////////////////////////////////////////////

// idle timer to keep the process updated since wx apparently doesn't do that
class IdleTimer : public wxTimer {
public:
  IdleTimer(SingleRunner::Pimpl* p) : pimpl_(p) {
  }
  void Notify();

  SingleRunner::Pimpl* pimpl_;
};

//////////////////////////////////////////////////////////////////////////

struct SingleRunner::Pimpl {
  explicit Pimpl(SingleRunner* p) : parent_(p), processes_(NULL), pid_(0), has_exit_code_(false), exit_code_(-1) {
    assert(parent_);
    idle_timer_.reset(new IdleTimer(this));
  }
  ~Pimpl();

  void Append(const wxString& s) {
    parent_->Append(s);
  }

  bool RunCmd(const Command& cmd);

  void Notify();

  void OnCompleted() {
    assert(parent_);
    parent_->Completed();
    idle_timer_->Stop();
  }

  SingleRunner* parent_;
  Process* processes_; // the current running process or NULL
  long pid_; // the id of the current or previous running process
  std::unique_ptr<IdleTimer> idle_timer_;

  int exit_code() const {
    assert(has_exit_code_);
    return exit_code_;
  }
  bool has_exit_code() const {
    return has_exit_code_;
  }
  void set_exit_code(int x) {
    exit_code_ = x;
    has_exit_code_ = true;
  }

private:
  bool has_exit_code_;
  int exit_code_;
};

void IdleTimer::Notify() {
  pimpl_->Notify();
}

class Process : public wxProcess
{
public:
  Process(SingleRunner::Pimpl* project, const wxString& cmd)
    : wxProcess(wxPROCESS_DEFAULT), cmd_(cmd)
  {
    runner_ = project;
    Redirect();
  }

  virtual void OnTerminate(int pid, int status) {
    assert(runner_);
    assert(runner_->pid_ == pid);

    // show the rest of the output
    while (HasInput()) {}

    runner_->Append(wxString::Format(wxT("Process %u ('%s') terminated with exit code %d."),
      pid, cmd_.c_str(), status));
    runner_->Append("");
    runner_->set_exit_code(status);
    runner_->OnCompleted();
  }

  virtual bool HasInput() {
    // original source: http://sourceforge.net/p/fourpane/code/HEAD/tree/trunk/ExecuteInDialog.cpp

    // The original used wxTextInputStream to read a line at a time.  Fine, except when there was no \n, whereupon the thing would hang
    // Instead, read the stream (which may occasionally contain non-ascii bytes e.g. from g++) into a memorybuffer, then to a wxString

    bool hasInput = false;

    while (IsInputAvailable()) {
      wxMemoryBuffer buf;
      do {
        const char c = GetInputStream()->GetC();

        if (GetInputStream()->Eof()) break;
        if (c == wxT('\n')) break;
        buf.AppendByte(c);
      } while (IsInputAvailable());

      wxString line((const char*)buf.GetData(), wxConvUTF8, buf.GetDataLen()); // Convert the line to utf8
      runner_->Append(line);
      hasInput = true;
    }

    while (IsErrorAvailable())
    {
      wxMemoryBuffer buf;
      do
      {
        const char c = GetErrorStream()->GetC();

        if (GetErrorStream()->Eof()) break;
        if (c == wxT('\n')) break;
        buf.AppendByte(c);
      } while (IsErrorAvailable());

      wxString line((const char*)buf.GetData(), wxConvUTF8, buf.GetDataLen());
      runner_->Append(line);
      hasInput = true;
    }

    return hasInput;
  }

protected:
  SingleRunner::Pimpl *runner_;
  wxString cmd_;
};

SingleRunner::Pimpl::~Pimpl() {
  delete processes_;
}

void SingleRunner::Pimpl::Notify(){
  if (processes_) {
    // sometimes the output hangs until we close the window
    // seems to be waiting for output or something
    // getting the input in a callback seems to remove the waiting...
    processes_->HasInput();
  }
}

bool SingleRunner::Pimpl::RunCmd(const Command& c) {
  Process* process = new Process(this, c.cmd);
  Append("> " + c.cmd);

  wxExecuteEnv env;
  env.cwd = c.root;

  const int flags = wxEXEC_ASYNC | RUNNER_CONSOLE_OPTION;

  const long process_id = wxExecute(c.cmd, flags, process, &env);

  // async call
  if (!process_id) {
    Append(wxT("Execution failed."));
    delete process;
    return false;
  }

  assert(processes_ == NULL);
  assert(pid_ == 0);
  processes_ = process;
  pid_ = process_id;

  idle_timer_->Start(100);
  return true;
}

//////////////////////////////////////////////////////////////////////////

SingleRunner::SingleRunner() : pimpl(new Pimpl(this)) {
}

SingleRunner::~SingleRunner() {
}

bool SingleRunner::RunCmd(const Command& cmd) {
  assert(pimpl);
  assert(this->IsRunning() == false);
  return pimpl->RunCmd(cmd);
}

bool SingleRunner::IsRunning() const {
  const bool has_process = pimpl->processes_ != NULL;
  if (has_process == false) return false;
  const bool exists = wxProcess::Exists(pimpl->processes_->GetPid());
  pimpl->processes_->HasInput();
  return !pimpl->has_exit_code();
}

void SingleRunner::Completed() {
  // empty
}

int SingleRunner::GetExitCode() {
  assert(this->IsRunning() == false);
  assert(pimpl->pid_ != 0);
  return pimpl->exit_code();
}

//////////////////////////////////////////////////////////////////////////

class MultiRunner::Runner : public SingleRunner {
public:
  Runner(MultiRunner* r) : runner_(r) {
    assert(runner_);
  }

  virtual void Append(const wxString& str) {
    assert(runner_);
    runner_->Append(str);
  }
  virtual void Completed() {
    assert(runner_);
    runner_->RunNext(GetExitCode());
  }
  bool Run(const Command& cmd) {
    return RunCmd(cmd);
  }
private:
  MultiRunner* runner_;
};

MultiRunner::MultiRunner(){
}

MultiRunner::~MultiRunner(){
}

bool MultiRunner::RunCmd(const Command& cmd) {
  commands_.push_back(cmd);
  if (IsRunning() == true) return true;
  return RunNext(0);
}

bool MultiRunner::RunNext(int last_exit_code) {
  assert(IsRunning() == false);
  if (commands_.empty()) return false;

  if (last_exit_code == 0) {
    last_runner_ = runner_;
    runner_.reset(new Runner(this));
    const bool run_result = runner_->Run(*commands_.begin());
    if (run_result) {
      commands_.erase(commands_.begin());
    }
    return run_result;
  }
  else {
    commands_.clear();
    return false;
  }
}

bool MultiRunner::IsRunning() const {
  if (runner_) {
    return runner_->IsRunning();
  }
  return false;
}
<|endoftext|>


<commit_before>/*
 * program to mimik university site.
 * source available at (Github repo - MIT licence):
 * http://dstjrd.ir/s/cppx
 * https://github.com/mohsend/cpp-examples
 */

#include <iostream>
#include "Csite.hpp"
#include "Cstudent.hpp"
#include "Clesson.hpp"

using namespace std;

int main()
{
	Clesson lessons[5];
	Cstudent stu("Mohsen Dastjedi Zade", "90259100270");

	stu.addLessonObj();
	Csite site(stu);
	site.mainMenu();

	return 0;
}
<commit_msg>changed a number<commit_after>/*
 * program to mimik university site.
 * source available at (Github repo - MIT licence):
 * http://dstjrd.ir/s/cppx
 * https://github.com/mohsend/cpp-examples
 */

#include <iostream>
#include "Csite.hpp"
#include "Cstudent.hpp"
#include "Clesson.hpp"

using namespace std;

int main()
{
	Clesson lessons[5];
	Cstudent stu("Mohsen Dastjedi Zade", "90000001");

	stu.addLessonObj();
	Csite site(stu);
	site.mainMenu();

	return 0;
}
<|endoftext|>