<commit_before>/* Copyright 2021, The TensorFlow Federated Authors.

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_federated/cc/core/impl/executors/executor_service.h"

#include <string>
#include <vector>

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/types/optional.h"
#include "tensorflow_federated/cc/core/impl/executors/cardinalities.h"
#include "tensorflow_federated/cc/core/impl/executors/executor.h"
#include "tensorflow_federated/cc/core/impl/executors/status_macros.h"
#include "tensorflow_federated/proto/v0/computation.pb.h"
#include "tensorflow_federated/proto/v0/executor.pb.h"

namespace tensorflow_federated {

#define TFF_TRYLOG_GRPC(status)               \
  ({                                          \
    grpc::Status __status = status;           \
    if (!__status.ok()) {                     \
      LOG(ERROR) << __status.error_message(); \
      return __status;                        \
    }                                         \
  })

grpc::Status ParseRef(const v0::ValueRef& value_ref_pb, ValueId* value_id_out) {
  if (absl::SimpleAtoi(value_ref_pb.id(), value_id_out)) {
    return grpc::Status::OK;
  }
  return grpc::Status(
      grpc::StatusCode::INVALID_ARGUMENT,
      absl::StrCat("Could not parse ValueRef from string. Incoming id:",
                   value_ref_pb.id()));
}

grpc::Status ExecutorService::RequireExecutor_(
    std::string method_name, std::shared_ptr<Executor>* executor_out,
    int* generation_out) {
  absl::ReaderMutexLock reader_lock(&executor_mutex_);
  if (executor_and_generation_.first == nullptr) {
    return grpc::Status(
        grpc::StatusCode::UNAVAILABLE,
        absl::StrCat("Attempted to call ExecutorService::", method_name,
                     " before setting cardinalities."));
  }
  *executor_out = executor_and_generation_.first;
  *generation_out = executor_and_generation_.second;
  return grpc::Status::OK;
}

ExecutorService::RemoteValueId ExecutorService::CreateRemoteValue_(
    ValueId embedded_value_id, int executor_generation) {
  return absl::StrCat(embedded_value_id, "-", executor_generation);
}

grpc::Status MalformattedValueStatus(absl::string_view bad_id) {
  return grpc::Status(
      grpc::StatusCode::INVALID_ARGUMENT,
      absl::StrCat("Remote value ID ", bad_id,
                   " malformed: expected to be of the form a-b, where a and "
                   "b are both ints."));
}

grpc::Status ExecutorService::EnsureGeneration_(int reference_generation,
                                                int expected_generation) {
  if (reference_generation != expected_generation) {
    return grpc::Status(
        grpc::StatusCode::INVALID_ARGUMENT,
        absl::StrCat("Remote value refers to a non-live executor generation. "
                     "Current generation is: ",
                     expected_generation, "remote valuerefers to generation: ",
                     reference_generation));
  }
  return grpc::Status::OK;
}

grpc::Status ExecutorService::ResolveRemoteValue_(
    const v0::ValueRef& remote_value_ref, int expected_generation,
    ValueId* value_id_out) {
  // Incoming ref should have ID of the form a-b, where a is a
  // uint64_t and b s an int. a represents the ValueId in the
  // service's executor, b represents the generation of this executor.
  std::vector<absl::string_view> id_and_generation =
      absl::StrSplit(remote_value_ref.id(), '-');
  if (id_and_generation.size() != 2) {
    return MalformattedValueStatus(remote_value_ref.id());
  }
  int reference_generation;
  if (!absl::SimpleAtoi(id_and_generation[1], &reference_generation)) {
    return MalformattedValueStatus(remote_value_ref.id());
  }
  TFF_TRYLOG_GRPC(EnsureGeneration_(reference_generation, expected_generation));
  if (!absl::SimpleAtoi(id_and_generation[0], value_id_out)) {
    return MalformattedValueStatus(remote_value_ref.id());
  }
  return grpc::Status::OK;
}

grpc::Status ExecutorService::CreateValue(grpc::ServerContext* context,
                                          const v0::CreateValueRequest* request,
                                          v0::CreateValueResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("CreateValue", &executor, &generation));
  absl::StatusOr<OwnedValueId> id = executor->CreateValue(request->value());
  if (!id.ok()) {
    LOG(ERROR) << id.status().message();
    return absl_to_grpc(id.status());
  }
  response->mutable_value_ref()->mutable_id()->assign(
      CreateRemoteValue_(id.value().ref(), generation));
  // We must call forget on the embedded id to prevent the destructor from
  // running when the variable goes out of scope. Similar considerations apply
  // to the reset of the Create methods below.
  id.value().forget();
  return grpc::Status::OK;
}

grpc::Status ExecutorService::CreateCall(grpc::ServerContext* context,
                                         const v0::CreateCallRequest* request,
                                         v0::CreateCallResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("CreateCall", &executor, &generation));
  ValueId embedded_fn;
  TFF_TRYLOG_GRPC(
      ResolveRemoteValue_(request->function_ref(), generation, &embedded_fn));
  absl::optional<ValueId> embedded_arg;
  if (request->has_argument_ref()) {
    // Callers should avoid setting the argument ref for invocation of a no-arg
    // fn.
    TFF_TRYLOG_GRPC(ResolveRemoteValue_(request->argument_ref(), generation,
                                        &embedded_arg.emplace()));
  }
  absl::StatusOr<OwnedValueId> called_fn =
      executor->CreateCall(embedded_fn, embedded_arg);
  if (!called_fn.ok()) {
    LOG(ERROR) << called_fn.status().message();
    return absl_to_grpc(called_fn.status());
  }
  response->mutable_value_ref()->mutable_id()->assign(
      CreateRemoteValue_(called_fn.value().ref(), generation));
  // We must prevent this destructor from running similarly to CreateValue.
  called_fn.value().forget();
  return grpc::Status::OK;
}

grpc::Status ExecutorService::CreateStruct(
    grpc::ServerContext* context, const v0::CreateStructRequest* request,
    v0::CreateStructResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("CreateStruct", &executor, &generation));
  std::vector<ValueId> requested_ids;
  requested_ids.reserve(request->element().size());
  for (const v0::CreateStructRequest::Element& elem : request->element()) {
    ValueId id;
    TFF_TRYLOG_GRPC(ResolveRemoteValue_(elem.value_ref(), generation, &id));
    requested_ids.push_back(id);
  }
  absl::StatusOr<OwnedValueId> created_struct =
      executor->CreateStruct(requested_ids);
  if (!created_struct.ok()) {
    LOG(ERROR) << created_struct.status().message();
    return absl_to_grpc(created_struct.status());
  }
  response->mutable_value_ref()->mutable_id()->assign(
      CreateRemoteValue_(created_struct.value().ref(), generation));
  // We must prevent this destructor from running similarly to CreateValue.
  created_struct.value().forget();
  return grpc::Status::OK;
}

grpc::Status ExecutorService::CreateSelection(
    grpc::ServerContext* context, const v0::CreateSelectionRequest* request,
    v0::CreateSelectionResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("CreateSelection", &executor, &generation));
  ValueId selection_source;
  TFF_TRYLOG_GRPC(ResolveRemoteValue_(request->source_ref(), generation,
                                      &selection_source));
  absl::StatusOr<OwnedValueId> selected_element =
      executor->CreateSelection(selection_source, request->index());
  if (!selected_element.ok()) {
    LOG(ERROR) << selected_element.status().message();
    return absl_to_grpc(selected_element.status());
  }
  response->mutable_value_ref()->mutable_id()->assign(
      CreateRemoteValue_(selected_element.value().ref(), generation));
  // We must prevent this destructor from running similarly to CreateValue.
  selected_element.value().forget();
  return grpc::Status::OK;
}

grpc::Status ExecutorService::Compute(grpc::ServerContext* context,
                                      const v0::ComputeRequest* request,
                                      v0::ComputeResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("Compute", &executor, &generation));
  ValueId requested_value;
  TFF_TRYLOG_GRPC(
      ResolveRemoteValue_(request->value_ref(), generation, &requested_value));
  absl::Status status =
      executor->Materialize(requested_value, response->mutable_value());
  return absl_to_grpc(status);
}

grpc::Status ExecutorService::SetCardinalities(
    grpc::ServerContext* context, const v0::SetCardinalitiesRequest* request,
    v0::SetCardinalitiesResponse* response) {
  CardinalityMap cardinality_map;
  for (const auto& cardinality : request->cardinalities()) {
    cardinality_map.insert(
        {cardinality.placement().uri(), cardinality.cardinality()});
  }
  {
    absl::WriterMutexLock writer_lock(&executor_mutex_);
    absl::StatusOr<std::shared_ptr<Executor>> new_executor =
        executor_factory_(cardinality_map);
    if (!new_executor.ok()) {
      LOG(ERROR) << new_executor.status().message();
      return absl_to_grpc(new_executor.status());
    }
    int new_generation = executor_and_generation_.second + 1;
    executor_and_generation_ =
        std::make_pair(std::move(new_executor.value()), new_generation);
  }
  return grpc::Status::OK;
}

grpc::Status ExecutorService::ClearExecutor(
    grpc::ServerContext* context, const v0::ClearExecutorRequest* request,
    v0::ClearExecutorResponse* response) {
  {
    absl::WriterMutexLock writer_lock(&executor_mutex_);
    // Clearing executor should reset executor to null, but without changing the
    // executor's generation; this will be incremented by SetCardinalities.
    executor_and_generation_ =
        std::make_pair(nullptr, executor_and_generation_.second);
  }
  return grpc::Status::OK;
}

grpc::Status ExecutorService::Dispose(grpc::ServerContext* context,
                                      const v0::DisposeRequest* request,
                                      v0::DisposeResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("Dispose", &executor, &generation));
  std::vector<ValueId> embedded_ids_to_dispose;
  embedded_ids_to_dispose.reserve(request->value_ref().size());
  // Filter the requested IDs to those corresponding to the currently live
  // executors. Clients are free to batch these requests however they want or
  // let them be called by a GC mechanism, so we do not force the client to only
  // dispose of values in the live executor.
  for (const v0::ValueRef& disposed_value_ref : request->value_ref()) {
    ValueId embedded_value;
    grpc::Status status =
        ResolveRemoteValue_(disposed_value_ref, generation, &embedded_value);
    if (status.ok()) {
      absl::Status absl_status = executor->Dispose(embedded_value);
      if (!absl_status.ok()) {
        LOG(ERROR) << absl_status.message();
        return absl_to_grpc(absl_status);
      }
    }
  }
  return grpc::Status::OK;
}

}  // namespace tensorflow_federated
<commit_msg>Fix spacing in executor service log message.<commit_after>/* Copyright 2021, The TensorFlow Federated Authors.

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_federated/cc/core/impl/executors/executor_service.h"

#include <string>
#include <vector>

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/types/optional.h"
#include "tensorflow_federated/cc/core/impl/executors/cardinalities.h"
#include "tensorflow_federated/cc/core/impl/executors/executor.h"
#include "tensorflow_federated/cc/core/impl/executors/status_macros.h"
#include "tensorflow_federated/proto/v0/computation.pb.h"
#include "tensorflow_federated/proto/v0/executor.pb.h"

namespace tensorflow_federated {

#define TFF_TRYLOG_GRPC(status)               \
  ({                                          \
    grpc::Status __status = status;           \
    if (!__status.ok()) {                     \
      LOG(ERROR) << __status.error_message(); \
      return __status;                        \
    }                                         \
  })

grpc::Status ParseRef(const v0::ValueRef& value_ref_pb, ValueId* value_id_out) {
  if (absl::SimpleAtoi(value_ref_pb.id(), value_id_out)) {
    return grpc::Status::OK;
  }
  return grpc::Status(
      grpc::StatusCode::INVALID_ARGUMENT,
      absl::StrCat("Could not parse ValueRef from string. Incoming id:",
                   value_ref_pb.id()));
}

grpc::Status ExecutorService::RequireExecutor_(
    std::string method_name, std::shared_ptr<Executor>* executor_out,
    int* generation_out) {
  absl::ReaderMutexLock reader_lock(&executor_mutex_);
  if (executor_and_generation_.first == nullptr) {
    return grpc::Status(
        grpc::StatusCode::UNAVAILABLE,
        absl::StrCat("Attempted to call ExecutorService::", method_name,
                     " before setting cardinalities."));
  }
  *executor_out = executor_and_generation_.first;
  *generation_out = executor_and_generation_.second;
  return grpc::Status::OK;
}

ExecutorService::RemoteValueId ExecutorService::CreateRemoteValue_(
    ValueId embedded_value_id, int executor_generation) {
  return absl::StrCat(embedded_value_id, "-", executor_generation);
}

grpc::Status MalformattedValueStatus(absl::string_view bad_id) {
  return grpc::Status(
      grpc::StatusCode::INVALID_ARGUMENT,
      absl::StrCat("Remote value ID ", bad_id,
                   " malformed: expected to be of the form a-b, where a and "
                   "b are both ints."));
}

grpc::Status ExecutorService::EnsureGeneration_(int reference_generation,
                                                int expected_generation) {
  if (reference_generation != expected_generation) {
    return grpc::Status(
        grpc::StatusCode::INVALID_ARGUMENT,
        absl::StrCat(
            "Remote value refers to a non-live executor generation. "
            "Current generation is: ",
            expected_generation,
            " remote value refers to generation: ", reference_generation));
  }
  return grpc::Status::OK;
}

grpc::Status ExecutorService::ResolveRemoteValue_(
    const v0::ValueRef& remote_value_ref, int expected_generation,
    ValueId* value_id_out) {
  // Incoming ref should have ID of the form a-b, where a is a
  // uint64_t and b s an int. a represents the ValueId in the
  // service's executor, b represents the generation of this executor.
  std::vector<absl::string_view> id_and_generation =
      absl::StrSplit(remote_value_ref.id(), '-');
  if (id_and_generation.size() != 2) {
    return MalformattedValueStatus(remote_value_ref.id());
  }
  int reference_generation;
  if (!absl::SimpleAtoi(id_and_generation[1], &reference_generation)) {
    return MalformattedValueStatus(remote_value_ref.id());
  }
  TFF_TRYLOG_GRPC(EnsureGeneration_(reference_generation, expected_generation));
  if (!absl::SimpleAtoi(id_and_generation[0], value_id_out)) {
    return MalformattedValueStatus(remote_value_ref.id());
  }
  return grpc::Status::OK;
}

grpc::Status ExecutorService::CreateValue(grpc::ServerContext* context,
                                          const v0::CreateValueRequest* request,
                                          v0::CreateValueResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("CreateValue", &executor, &generation));
  absl::StatusOr<OwnedValueId> id = executor->CreateValue(request->value());
  if (!id.ok()) {
    LOG(ERROR) << id.status().message();
    return absl_to_grpc(id.status());
  }
  response->mutable_value_ref()->mutable_id()->assign(
      CreateRemoteValue_(id.value().ref(), generation));
  // We must call forget on the embedded id to prevent the destructor from
  // running when the variable goes out of scope. Similar considerations apply
  // to the reset of the Create methods below.
  id.value().forget();
  return grpc::Status::OK;
}

grpc::Status ExecutorService::CreateCall(grpc::ServerContext* context,
                                         const v0::CreateCallRequest* request,
                                         v0::CreateCallResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("CreateCall", &executor, &generation));
  ValueId embedded_fn;
  TFF_TRYLOG_GRPC(
      ResolveRemoteValue_(request->function_ref(), generation, &embedded_fn));
  absl::optional<ValueId> embedded_arg;
  if (request->has_argument_ref()) {
    // Callers should avoid setting the argument ref for invocation of a no-arg
    // fn.
    TFF_TRYLOG_GRPC(ResolveRemoteValue_(request->argument_ref(), generation,
                                        &embedded_arg.emplace()));
  }
  absl::StatusOr<OwnedValueId> called_fn =
      executor->CreateCall(embedded_fn, embedded_arg);
  if (!called_fn.ok()) {
    LOG(ERROR) << called_fn.status().message();
    return absl_to_grpc(called_fn.status());
  }
  response->mutable_value_ref()->mutable_id()->assign(
      CreateRemoteValue_(called_fn.value().ref(), generation));
  // We must prevent this destructor from running similarly to CreateValue.
  called_fn.value().forget();
  return grpc::Status::OK;
}

grpc::Status ExecutorService::CreateStruct(
    grpc::ServerContext* context, const v0::CreateStructRequest* request,
    v0::CreateStructResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("CreateStruct", &executor, &generation));
  std::vector<ValueId> requested_ids;
  requested_ids.reserve(request->element().size());
  for (const v0::CreateStructRequest::Element& elem : request->element()) {
    ValueId id;
    TFF_TRYLOG_GRPC(ResolveRemoteValue_(elem.value_ref(), generation, &id));
    requested_ids.push_back(id);
  }
  absl::StatusOr<OwnedValueId> created_struct =
      executor->CreateStruct(requested_ids);
  if (!created_struct.ok()) {
    LOG(ERROR) << created_struct.status().message();
    return absl_to_grpc(created_struct.status());
  }
  response->mutable_value_ref()->mutable_id()->assign(
      CreateRemoteValue_(created_struct.value().ref(), generation));
  // We must prevent this destructor from running similarly to CreateValue.
  created_struct.value().forget();
  return grpc::Status::OK;
}

grpc::Status ExecutorService::CreateSelection(
    grpc::ServerContext* context, const v0::CreateSelectionRequest* request,
    v0::CreateSelectionResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("CreateSelection", &executor, &generation));
  ValueId selection_source;
  TFF_TRYLOG_GRPC(ResolveRemoteValue_(request->source_ref(), generation,
                                      &selection_source));
  absl::StatusOr<OwnedValueId> selected_element =
      executor->CreateSelection(selection_source, request->index());
  if (!selected_element.ok()) {
    LOG(ERROR) << selected_element.status().message();
    return absl_to_grpc(selected_element.status());
  }
  response->mutable_value_ref()->mutable_id()->assign(
      CreateRemoteValue_(selected_element.value().ref(), generation));
  // We must prevent this destructor from running similarly to CreateValue.
  selected_element.value().forget();
  return grpc::Status::OK;
}

grpc::Status ExecutorService::Compute(grpc::ServerContext* context,
                                      const v0::ComputeRequest* request,
                                      v0::ComputeResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("Compute", &executor, &generation));
  ValueId requested_value;
  TFF_TRYLOG_GRPC(
      ResolveRemoteValue_(request->value_ref(), generation, &requested_value));
  absl::Status status =
      executor->Materialize(requested_value, response->mutable_value());
  return absl_to_grpc(status);
}

grpc::Status ExecutorService::SetCardinalities(
    grpc::ServerContext* context, const v0::SetCardinalitiesRequest* request,
    v0::SetCardinalitiesResponse* response) {
  CardinalityMap cardinality_map;
  for (const auto& cardinality : request->cardinalities()) {
    cardinality_map.insert(
        {cardinality.placement().uri(), cardinality.cardinality()});
  }
  {
    absl::WriterMutexLock writer_lock(&executor_mutex_);
    absl::StatusOr<std::shared_ptr<Executor>> new_executor =
        executor_factory_(cardinality_map);
    if (!new_executor.ok()) {
      LOG(ERROR) << new_executor.status().message();
      return absl_to_grpc(new_executor.status());
    }
    int new_generation = executor_and_generation_.second + 1;
    executor_and_generation_ =
        std::make_pair(std::move(new_executor.value()), new_generation);
  }
  return grpc::Status::OK;
}

grpc::Status ExecutorService::ClearExecutor(
    grpc::ServerContext* context, const v0::ClearExecutorRequest* request,
    v0::ClearExecutorResponse* response) {
  {
    absl::WriterMutexLock writer_lock(&executor_mutex_);
    // Clearing executor should reset executor to null, but without changing the
    // executor's generation; this will be incremented by SetCardinalities.
    executor_and_generation_ =
        std::make_pair(nullptr, executor_and_generation_.second);
  }
  return grpc::Status::OK;
}

grpc::Status ExecutorService::Dispose(grpc::ServerContext* context,
                                      const v0::DisposeRequest* request,
                                      v0::DisposeResponse* response) {
  std::shared_ptr<Executor> executor;
  int generation;
  TFF_TRYLOG_GRPC(RequireExecutor_("Dispose", &executor, &generation));
  std::vector<ValueId> embedded_ids_to_dispose;
  embedded_ids_to_dispose.reserve(request->value_ref().size());
  // Filter the requested IDs to those corresponding to the currently live
  // executors. Clients are free to batch these requests however they want or
  // let them be called by a GC mechanism, so we do not force the client to only
  // dispose of values in the live executor.
  for (const v0::ValueRef& disposed_value_ref : request->value_ref()) {
    ValueId embedded_value;
    grpc::Status status =
        ResolveRemoteValue_(disposed_value_ref, generation, &embedded_value);
    if (status.ok()) {
      absl::Status absl_status = executor->Dispose(embedded_value);
      if (!absl_status.ok()) {
        LOG(ERROR) << absl_status.message();
        return absl_to_grpc(absl_status);
      }
    }
  }
  return grpc::Status::OK;
}

}  // namespace tensorflow_federated
<|endoftext|>


<commit_before>////////////////////////////////////////
//  test lcio::TrackerHit
////////////////////////////////////////

#include "tutil.h"
#include "lcio.h"

#include "EVENT/LCIO.h"
#include "IO/LCReader.h"
#include "IO/LCWriter.h"
#include "IMPL/LCEventImpl.h"
#include "IMPL/LCCollectionVec.h"
#include "IMPL/TrackerHitImpl.h"
#include "IMPL/LCFlagImpl.h"
//#include "UTIL/Operators.h"

#include "UTIL/CellIDEncoder.h"
#include "UTIL/CellIDDecoder.h"
#include "UTIL/ILDConf.h"

//#include <iostream>

using namespace std ;
using namespace lcio ;

//static const int NRUN = 10 ;
static const int NEVENT = 10 ; // events
static const int NHITS = 1000 ;  // tracker hits per event

static string FILEN = "trackerhits.slcio" ;

// replace mytest with the name of your test
const static string testname="test_trackerhit";

//=============================================================================

int main(int /*argc*/, char** /*argv*/ ){

    // this should be the first line in your test
    TEST MYTEST=TEST( testname, std::cout );

    try{

        MYTEST.LOG( " writing TrackerHits " );

        // create sio writer
        LCWriter* lcWrt = LCFactory::getInstance()->createLCWriter()  ;

        lcWrt->open( FILEN , LCIO::WRITE_NEW ) ;

        // EventLoop - create some events and write them to the file
        for(int i=0;i<NEVENT;i++){

            // we need to use the implementation classes here
            LCEventImpl*  evt = new LCEventImpl() ;

            evt->setRunNumber( 4711  ) ;
            evt->setEventNumber( i ) ;

            LCCollectionVec* trkHits = new LCCollectionVec( LCIO::TRACKERHIT )  ;

	    ILDCellIDEncoder<TrackerHitImpl> idEnc( "readoutUnit:8,daqChannel:16,"  ,   trkHits ) ;
	    //   this is effectively the same as:
	    //	 CellIDEncoder<TrackerHitImpl> idEnc( ILDCellID0::encoder_string + ",readoutUnit:8,daqChannel:16"  ,   trkHits ) ;

            for(int j=0;j<NHITS;j++){

	      TrackerHitImpl* trkHit = new TrackerHitImpl ;

	      idEnc.reset() ;

	      idEnc[ ILDCellID0::subdet ]  = ILDDetID::FTD ;
	      idEnc[ ILDCellID0::layer  ]  = j % 100 ;
	      idEnc[ ILDCellID0::side   ]  = ILDDetID::bwd ;
	      idEnc[ ILDCellID0::module ]  = j / 100 + 1 ;
	      idEnc[ ILDCellID0::sensor ]  = j % 4  ;
	      idEnc["daqChannel"] =  j*8 ;

	      idEnc.setCellID( trkHit ) ;

	      trkHit->setEDep( i*j*117. ) ;
	      // trkHit->setdEdx( i*j*117. ) ;
	      trkHit->setEDepError( (i+j)*.3 ) ;
	      double pos[3] = { 1.*i, 1.*j, 1.*i*j } ;
	      trkHit->setPosition( pos ) ;

	      float cov[TRKHITNCOVMATRIX] = { float(i), float(j), float(i+j) , float(2*i), float(2.*j), float(2.*(i+j) ) } ;
	      trkHit->setCovMatrix( cov );

	      trkHits->addElement( trkHit ) ;
            }
            evt->addCollection( trkHits , "TrackerHits") ;

            lcWrt->writeEvent(evt) ;

            delete evt ;
        }

        lcWrt->close() ;

        MYTEST.LOG(" reading back TrackerHits from file " ) ;

        // create sio reader
        LCReader* lcRdr = LCFactory::getInstance()->createLCReader()  ;

        lcRdr->open( FILEN ) ;

        for(int i=0;i<NEVENT;i++){

            //std::cout << " testing event " << i << std::endl ;

            LCEvent*  evt =  lcRdr->readNextEvent() ;

            MYTEST( evt->getRunNumber() ,  4711 , " run number " )  ;

            MYTEST(  evt->getEventNumber() ,  i , " event number "  ) ;

            LCCollection* trkHits = evt->getCollection( "TrackerHits") ;

	    CellIDDecoder<TrackerHit> idDec( trkHits ) ;

            for(int j=0;j<NHITS;j++) {

                //std::cout << " testing hit " << j << std::endl ;

                TrackerHit* trkHit = dynamic_cast<TrackerHit*>(trkHits->getElementAt(j)) ;

		MYTEST( idDec(trkHit)[ ILDCellID0::subdet ]  , ILDDetID::FTD , " cellID(trkHit) == ( ILDDetID::FTD  ) " ) ;
		MYTEST( idDec(trkHit)[ ILDCellID0::layer  ]  , j % 100       , " cellID(trkHit) == ( j % 100        ) " ) ;
		MYTEST( idDec(trkHit)[ ILDCellID0::side   ]  , ILDDetID::bwd , " cellID(trkHit) == ( ILDDetID::bwd  ) " ) ;
		MYTEST( idDec(trkHit)[ ILDCellID0::module ]  , j / 100 + 1   , " cellID(trkHit) == ( j / 100 + 1    ) " ) ;
		MYTEST( idDec(trkHit)[ ILDCellID0::sensor ]  , j % 4         , " cellID(trkHit) == ( j % 4          ) " ) ;
		MYTEST( idDec(trkHit)["daqChannel"]          , j*8           , " cellID(trkHit) == ( j*8            ) " ) ;

                //std::cout << *trkHit << std::endl ;

                MYTEST( trkHit->getEDep() ,  i*j*117. , "EDep" ) ;

		// MYTEST( trkHit->getdEdx() ,  i*j*117. , "dEdx" ) ;
                // remove float converstion and check what happens ;)
                MYTEST( trkHit->getEDepError() ,  float((i+j)*.3) , "EDepError" ) ;
                //MYTEST( trkHit->getEDepError() ,  (i+j)*.3 , "EDepError" ) ;

                const double* pos = trkHit->getPosition() ;

                MYTEST( pos[0] , i , " pos[0] " ) ;
                MYTEST( pos[1] , j , " pos[1] " ) ;
                MYTEST( pos[2] , i*j , " pos[2] " ) ;

                const FloatVec& cov = trkHit->getCovMatrix() ;

                MYTEST( cov[0] , i , " cov[0] " ) ;
                MYTEST( cov[1] , j , " cov[1] " ) ;
                MYTEST( cov[2] , i+j , " cov[2] " ) ;

            }
        }
        lcRdr->close() ;

    } catch( Exception &e ){
        MYTEST.FAILED( e.what() );
    }

    return 0;
}

//=============================================================================

<commit_msg>Replace ILDCellID0 with LCTrackerCellID<commit_after>////////////////////////////////////////
//  test lcio::TrackerHit
////////////////////////////////////////

#include "tutil.h"
#include "lcio.h"

#include "EVENT/LCIO.h"
#include "IO/LCReader.h"
#include "IO/LCWriter.h"
#include "IMPL/LCEventImpl.h"
#include "IMPL/LCCollectionVec.h"
#include "IMPL/TrackerHitImpl.h"
#include "IMPL/LCFlagImpl.h"
//#include "UTIL/Operators.h"

#include "UTIL/CellIDEncoder.h"
#include "UTIL/CellIDDecoder.h"
#include "UTIL/ILDConf.h"
#include "UTIL/LCTrackerConf.h"

//#include <iostream>

using namespace std ;
using namespace lcio ;

//static const int NRUN = 10 ;
static const int NEVENT = 10 ; // events
static const int NHITS = 1000 ;  // tracker hits per event

static string FILEN = "trackerhits.slcio" ;

// replace mytest with the name of your test
const static string testname="test_trackerhit";

//=============================================================================

int main(int /*argc*/, char** /*argv*/ ){

    // this should be the first line in your test
    TEST MYTEST=TEST( testname, std::cout );

    try{

        MYTEST.LOG( " writing TrackerHits " );

        // create sio writer
        LCWriter* lcWrt = LCFactory::getInstance()->createLCWriter()  ;

        lcWrt->open( FILEN , LCIO::WRITE_NEW ) ;

        // EventLoop - create some events and write them to the file
        for(int i=0;i<NEVENT;i++){

            // we need to use the implementation classes here
            LCEventImpl*  evt = new LCEventImpl() ;

            evt->setRunNumber( 4711  ) ;
            evt->setEventNumber( i ) ;

            LCCollectionVec* trkHits = new LCCollectionVec( LCIO::TRACKERHIT )  ;

	    ILDCellIDEncoder<TrackerHitImpl> idEnc( "readoutUnit:8,daqChannel:16,"  ,   trkHits ) ;
	    //   this is effectively the same as:
	    //	 CellIDEncoder<TrackerHitImpl> idEnc( LCTrackerCellID::encoding_string() + ",readoutUnit:8,daqChannel:16"  ,   trkHits ) ;

            for(int j=0;j<NHITS;j++){

	      TrackerHitImpl* trkHit = new TrackerHitImpl ;

	      idEnc.reset() ;

	      idEnc[ LCTrackerCellID::subdet() ]  = ILDDetID::FTD ;
	      idEnc[ LCTrackerCellID::layer() ]  = j % 100 ;
	      idEnc[ LCTrackerCellID::side()   ]  = ILDDetID::bwd ;
	      idEnc[ LCTrackerCellID::module() ]  = j / 100 + 1 ;
	      idEnc[ LCTrackerCellID::sensor() ]  = j % 4  ;
	      idEnc["daqChannel"] =  j*8 ;

	      idEnc.setCellID( trkHit ) ;

	      trkHit->setEDep( i*j*117. ) ;
	      // trkHit->setdEdx( i*j*117. ) ;
	      trkHit->setEDepError( (i+j)*.3 ) ;
	      double pos[3] = { 1.*i, 1.*j, 1.*i*j } ;
	      trkHit->setPosition( pos ) ;

	      float cov[TRKHITNCOVMATRIX] = { float(i), float(j), float(i+j) , float(2*i), float(2.*j), float(2.*(i+j) ) } ;
	      trkHit->setCovMatrix( cov );

	      trkHits->addElement( trkHit ) ;
            }
            evt->addCollection( trkHits , "TrackerHits") ;

            lcWrt->writeEvent(evt) ;

            delete evt ;
        }

        lcWrt->close() ;

        MYTEST.LOG(" reading back TrackerHits from file " ) ;

        // create sio reader
        LCReader* lcRdr = LCFactory::getInstance()->createLCReader()  ;

        lcRdr->open( FILEN ) ;

        for(int i=0;i<NEVENT;i++){

            //std::cout << " testing event " << i << std::endl ;

            LCEvent*  evt =  lcRdr->readNextEvent() ;

            MYTEST( evt->getRunNumber() ,  4711 , " run number " )  ;

            MYTEST(  evt->getEventNumber() ,  i , " event number "  ) ;

            LCCollection* trkHits = evt->getCollection( "TrackerHits") ;

	    CellIDDecoder<TrackerHit> idDec( trkHits ) ;

            for(int j=0;j<NHITS;j++) {

                //std::cout << " testing hit " << j << std::endl ;

                TrackerHit* trkHit = dynamic_cast<TrackerHit*>(trkHits->getElementAt(j)) ;

		MYTEST( idDec(trkHit)[ LCTrackerCellID::subdet() ]  , ILDDetID::FTD , " cellID(trkHit) == ( ILDDetID::FTD  ) " ) ;
		MYTEST( idDec(trkHit)[ LCTrackerCellID::layer()  ]  , j % 100       , " cellID(trkHit) == ( j % 100        ) " ) ;
		MYTEST( idDec(trkHit)[ LCTrackerCellID::side()   ]  , ILDDetID::bwd , " cellID(trkHit) == ( ILDDetID::bwd  ) " ) ;
		MYTEST( idDec(trkHit)[ LCTrackerCellID::module() ]  , j / 100 + 1   , " cellID(trkHit) == ( j / 100 + 1    ) " ) ;
		MYTEST( idDec(trkHit)[ LCTrackerCellID::sensor() ]  , j % 4         , " cellID(trkHit) == ( j % 4          ) " ) ;
		MYTEST( idDec(trkHit)["daqChannel"]          , j*8           , " cellID(trkHit) == ( j*8            ) " ) ;

                //std::cout << *trkHit << std::endl ;

                MYTEST( trkHit->getEDep() ,  i*j*117. , "EDep" ) ;

		// MYTEST( trkHit->getdEdx() ,  i*j*117. , "dEdx" ) ;
                // remove float converstion and check what happens ;)
                MYTEST( trkHit->getEDepError() ,  float((i+j)*.3) , "EDepError" ) ;
                //MYTEST( trkHit->getEDepError() ,  (i+j)*.3 , "EDepError" ) ;

                const double* pos = trkHit->getPosition() ;

                MYTEST( pos[0] , i , " pos[0] " ) ;
                MYTEST( pos[1] , j , " pos[1] " ) ;
                MYTEST( pos[2] , i*j , " pos[2] " ) ;

                const FloatVec& cov = trkHit->getCovMatrix() ;

                MYTEST( cov[0] , i , " cov[0] " ) ;
                MYTEST( cov[1] , j , " cov[1] " ) ;
                MYTEST( cov[2] , i+j , " cov[2] " ) ;

            }
        }
        lcRdr->close() ;

    } catch( Exception &e ){
        MYTEST.FAILED( e.what() );
    }

    return 0;
}

//=============================================================================

<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <array>

// template <class T, size_t N> void swap(array<T,N>& x, array<T,N>& y);

#include <array>
#include <cassert>

#include "test_macros.h"
// std::array is explicitly allowed to be initialized with A a = { init-list };.
// Disable the missing braces warning for this reason.
#include "disable_missing_braces_warning.h"

struct NonSwappable {
  NonSwappable() {}
private:
  NonSwappable(NonSwappable const&);
  NonSwappable& operator=(NonSwappable const&);
};

template <class Tp>
decltype(swap(std::declval<Tp>(), std::declval<Tp>()))
can_swap_imp(int);

template <class Tp>
std::false_type can_swap_imp(...);

template <class Tp>
struct can_swap : std::is_same<decltype(can_swap_imp<Tp>(0)), void> {};

int main()
{
    {
        typedef double T;
        typedef std::array<T, 3> C;
        C c1 = {1, 2, 3.5};
        C c2 = {4, 5, 6.5};
        swap(c1, c2);
        assert(c1.size() == 3);
        assert(c1[0] == 4);
        assert(c1[1] == 5);
        assert(c1[2] == 6.5);
        assert(c2.size() == 3);
        assert(c2[0] == 1);
        assert(c2[1] == 2);
        assert(c2[2] == 3.5);
    }
    {
        typedef double T;
        typedef std::array<T, 0> C;
        C c1 = {};
        C c2 = {};
        swap(c1, c2);
        assert(c1.size() == 0);
        assert(c2.size() == 0);
    }
    {
        typedef NonSwappable T;
        typedef std::array<T, 42> C1;
        typedef std::array<T, 0> C0;
        static_assert(!can_swap<C1&>::value, "");
        static_assert(can_swap<C0&>::value, "");
        C0 l = {};
        C0 r = {};
        swap(l, r);
#if TEST_STD_VER >= 11
        static_assert(noexcept(swap(l, r)), "");
#endif
    }
}
<commit_msg>Fix C++03 build breakage<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <array>

// template <class T, size_t N> void swap(array<T,N>& x, array<T,N>& y);

#include <array>
#include <cassert>

#include "test_macros.h"
// std::array is explicitly allowed to be initialized with A a = { init-list };.
// Disable the missing braces warning for this reason.
#include "disable_missing_braces_warning.h"

struct NonSwappable {
  NonSwappable() {}
private:
  NonSwappable(NonSwappable const&);
  NonSwappable& operator=(NonSwappable const&);
};

template <class Tp>
decltype(swap(std::declval<Tp>(), std::declval<Tp>()))
can_swap_imp(int);

template <class Tp>
std::false_type can_swap_imp(...);

template <class Tp>
struct can_swap : std::is_same<decltype(can_swap_imp<Tp>(0)), void> {};

int main()
{
    {
        typedef double T;
        typedef std::array<T, 3> C;
        C c1 = {1, 2, 3.5};
        C c2 = {4, 5, 6.5};
        swap(c1, c2);
        assert(c1.size() == 3);
        assert(c1[0] == 4);
        assert(c1[1] == 5);
        assert(c1[2] == 6.5);
        assert(c2.size() == 3);
        assert(c2[0] == 1);
        assert(c2[1] == 2);
        assert(c2[2] == 3.5);
    }
    {
        typedef double T;
        typedef std::array<T, 0> C;
        C c1 = {};
        C c2 = {};
        swap(c1, c2);
        assert(c1.size() == 0);
        assert(c2.size() == 0);
    }
    {
        typedef NonSwappable T;
        typedef std::array<T, 0> C0;
        static_assert(can_swap<C0&>::value, "");
        C0 l = {};
        C0 r = {};
        swap(l, r);
#if TEST_STD_VER >= 11
        static_assert(noexcept(swap(l, r)), "");
#endif
    }
#if TEST_STD_VER >= 11
    {
        // NonSwappable is still considered swappable in C++03 because there
        // is no access control SFINAE.
        typedef NonSwappable T;
        typedef std::array<T, 42> C1;
        static_assert(!can_swap<C1&>::value, "");
    }
#endif
}
<|endoftext|>


<commit_before>// Copyright © 2014 Lénaïc Bagnères, hnc@singularity.fr

// This file is part of hnc.

// hnc is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// hnc is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with hnc. If not, see <http://www.gnu.org/licenses/>

#ifndef HNC_INT_HPP
#define HNC_INT_HPP

#include "int/int8.hpp"
#include "int/uint8.hpp"

namespace hnc
{
	/// @brief Typedef for unsigned int
	using uint_t = unsigned int;
}

#endif
<commit_msg>Add hnc::luint_t typedef<commit_after>// Copyright © 2014 Lénaïc Bagnères, hnc@singularity.fr

// This file is part of hnc.

// hnc is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// hnc is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with hnc. If not, see <http://www.gnu.org/licenses/>

#ifndef HNC_INT_HPP
#define HNC_INT_HPP

#include "int/int8.hpp"
#include "int/uint8.hpp"

namespace hnc
{
	/// @brief Typedef for unsigned int
	using uint_t = unsigned int;

	/// @brief Typedef for long unsigned int
	using luint_t = unsigned int;
}

#endif
<|endoftext|>


<commit_before>// Copyright 2017, Dawid Kurek, <dawikur@gmail.com>

#ifndef INCLUDE_LEL_BOX_HPP_
#define INCLUDE_LEL_BOX_HPP_

#include <type_traits>

namespace LeL {

template <class Type, Type... Tokens>
struct Box {
 private:
  template <Type... Values>
  using Self = Box<Type, Values...>;

  template <int Index, Type Token, Type... Tail>
  struct IndexOfImpl {
    static_assert(sizeof...(Tail) != 0, "Index not found");
  };

  template <class Merged, class Left, class Right>
  struct MergeImpl;

 public:
  template <class>
  struct Merge;

  template <Type... NewTokens>
  struct Merge<Self<NewTokens...>> {
    using Result =
      typename MergeImpl<Self<>, Self<Tokens...>, Self<NewTokens...>>::Result;
  };

  template <Type       Token>
  static constexpr int IndexOf() noexcept {
    return IndexOfImpl<0, Token, Tokens...>::Result::value;
  }

  template <Type... NewTokens>
  using IndexesOf = Box<int, (IndexOf<NewTokens>())...>;

 private:
  template <int Index, Type Token, Type Head, Type... Tail>
  struct IndexOfImpl<Index, Token, Head, Tail...>
    : public IndexOfImpl<Index + 1, Token, Tail...> {};

  template <int Index, Type Token, Type... Tail>
  struct IndexOfImpl<Index, Token, Token, Tail...> {
    using Result = std::integral_constant<int, Index>;
  };

  // Finish: only left
  template <Type... Merged, Type... Left>
  struct MergeImpl<Self<Merged...>, Self<Left...>, Self<>> {
    using Result = Self<Merged..., Left...>;
  };

  // Finish: only right
  template <Type... Merged, Type... Right>
  struct MergeImpl<Self<Merged...>, Self<>, Self<Right...>> {
    using Result = Self<Merged..., Right...>;
  };

  // Finish: nothing left to do
  template <Type... Merged>
  struct MergeImpl<Self<Merged...>, Self<>, Self<>> {
    using Result = Self<Merged...>;
  };

  // Heads are the same in Left and Right
  template <Type... Merged,
            Type Head,
            Type... TailL,
            Type... TailR>
  struct MergeImpl<Self<Merged...>,
                   Self<Head, TailL...>,
                   Self<Head, TailR...>>
    : public MergeImpl<Self<Merged..., Head>,
                       Self<TailL...>,
                       Self<TailR...>> {};

  template <class Left, class Right, bool Condition>
  struct Choose;

  // Compare first elements from Left and Right
  template <Type... Merged,
            Type HeadL,
            Type... TailL,
            Type HeadR,
            Type... TailR>
  struct MergeImpl<Self<Merged...>,
                   Self<HeadL, TailL...>,
                   Self<HeadR, TailR...>>
    : public MergeImpl<Self<Merged...,
                            Choose<Self<HeadL, TailL...>,
                                   Self<HeadR, TailR...>,
                                   (HeadL < HeadR)>::Lower>,
                       typename Choose<Self<HeadL, TailL...>,
                                       Self<HeadR, TailR...>,
                                       (HeadL < HeadR)>::Left,
                       typename Choose<Self<HeadL, TailL...>,
                                       Self<HeadR, TailR...>,
                                       (HeadL < HeadR)>::Right> {};

  // Left is lower
  template <Type... TailL, Type HeadR, Type... TailR>
  struct Choose<Self<TailL...>, Self<HeadR, TailR...>, false> {
    static constexpr Type const Lower = HeadR;
    using Left  = Self<TailL...>;
    using Right = Self<TailR...>;
  };

  // Right is lower
  template <Type HeadL, Type... TailL, Type... TailR>
  struct Choose<Self<HeadL, TailL...>, Self<TailR...>, true> {
    static constexpr Type const Lower = HeadL;
    using Left  = Self<TailL...>;
    using Right = Self<TailR...>;
  };

  // TODO: 2017-07-10 check if sequences are sored & unique
};

template <class Left, class Right>
using Merge = typename Left::template Merge<Right>::Result;

}  // namespace LeL

#endif  // INCLUDE_LEL_BOX_HPP_
<commit_msg>Try to fix VS compilation<commit_after>// Copyright 2017, Dawid Kurek, <dawikur@gmail.com>

#ifndef INCLUDE_LEL_BOX_HPP_
#define INCLUDE_LEL_BOX_HPP_

#include <type_traits>

namespace LeL {

template <class Type, Type... Tokens>
struct Box {
 private:
  template <Type... Values>
  using Self = Box<Type, Values...>;

  template <int Index, Type Token, Type... Tail>
  struct IndexOfImpl {
    static_assert(sizeof...(Tail) != 0, "Index not found");
  };

  template <class Merged, class Left, class Right>
  struct MergeImpl;

 public:
  template <class>
  struct Merge;

  template <Type... NewTokens>
  struct Merge<Self<NewTokens...>> {
    using Result =
      typename MergeImpl<Self<>, Self<Tokens...>, Self<NewTokens...>>::Result;
  };

  template <Type       Token>
  static constexpr int IndexOf() noexcept {
    return IndexOfImpl<0, Token, Tokens...>::Result::value;
  }

  template <Type... NewTokens>
  using IndexesOf = Box<int, (IndexOf<NewTokens>())...>;

 private:
  template <int Index, Type Token, Type Head, Type... Tail>
  struct IndexOfImpl<Index, Token, Head, Tail...>
    : public IndexOfImpl<Index + 1, Token, Tail...> {};

  template <int Index, Type Token, Type... Tail>
  struct IndexOfImpl<Index, Token, Token, Tail...> {
    using Result = std::integral_constant<int, Index>;
  };

  // Finish: only left
  template <Type... Merged, Type... Left>
  struct MergeImpl<Self<Merged...>, Self<Left...>, Self<>> {
    using Result = Self<Merged..., Left...>;
  };

  // Finish: only right
  template <Type... Merged, Type... Right>
  struct MergeImpl<Self<Merged...>, Self<>, Self<Right...>> {
    using Result = Self<Merged..., Right...>;
  };

  // Finish: nothing left to do
  template <Type... Merged>
  struct MergeImpl<Self<Merged...>, Self<>, Self<>> {
    using Result = Self<Merged...>;
  };

  // Heads are the same in Left and Right
  template <Type... Merged,
            Type Head,
            Type... TailL,
            Type... TailR>
  struct MergeImpl<Self<Merged...>,
                   Self<Head, TailL...>,
                   Self<Head, TailR...>>
    : public MergeImpl<Self<Merged..., Head>,
                       Self<TailL...>,
                       Self<TailR...>> {};

  template <Type Left, Type Right>
  static constexpr Type const Lower = Left < Right ? Left : Right;

  template <class Left, class Right, bool Condition>
  struct Choose;

  // Compare first elements from Left and Right
  template <Type... Merged,
            Type HeadL,
            Type... TailL,
            Type HeadR,
            Type... TailR>
  struct MergeImpl<Self<Merged...>,
                   Self<HeadL, TailL...>,
                   Self<HeadR, TailR...>>
    : public MergeImpl<Self<Merged..., Lower<HeadL, HeadR>>,
                       typename Choose<Self<HeadL, TailL...>,
                                       Self<HeadR, TailR...>,
                                       (HeadL < HeadR)>::Left,
                       typename Choose<Self<HeadL, TailL...>,
                                       Self<HeadR, TailR...>,
                                       (HeadL < HeadR)>::Right> {};

  // Left is lower
  template <Type... TailL, Type HeadR, Type... TailR>
  struct Choose<Self<TailL...>, Self<HeadR, TailR...>, false> {
    using Left  = Self<TailL...>;
    using Right = Self<TailR...>;
  };

  // Right is lower
  template <Type HeadL, Type... TailL, Type... TailR>
  struct Choose<Self<HeadL, TailL...>, Self<TailR...>, true> {
    using Left  = Self<TailL...>;
    using Right = Self<TailR...>;
  };

  // TODO: 2017-07-10 check if sequences are sored & unique
};

template <class Left, class Right>
using Merge = typename Left::template Merge<Right>::Result;

}  // namespace LeL

#endif  // INCLUDE_LEL_BOX_HPP_
<|endoftext|>


<commit_before>#include "../testsettings.hpp"

#if TEST_DURATION > 0

#include "tightdb/column.hpp"
#include <UnitTest++.h>
#include <vector>
#include <algorithm>
#include "verified_integer.hpp"
#include "tightdb/query_conditions.hpp"

using namespace tightdb;

namespace {

uint64_t rand2(int bitwidth = 64)
{
    uint64_t i = (int64_t)rand() * (int64_t)rand() * (int64_t)rand() * (int64_t)rand() * (int64_t)rand();
    if(bitwidth < 64) {
        const uint64_t mask = ((1ULL << bitwidth) - 1ULL);
        i &= mask;
    }
    return i;
}

}

TEST(LESS)
{
    int64_t v[13] = {0, 1, 3, 15, 100, 30000, 1000000LL, 1000LL*1000LL*1000LL*1000LL, -15, -100, -30000, -1000000ULL, -1000ULL*1000LL*1000LL*1000LL};

    for (size_t w = 0; w < 13; w++) {
        const size_t LEN = 64 * 8; // to create at least 64 bytes of data (2 * 128-bit SSE chunks + 64 bit chunk before and after + some unaligned data before and after)
        Array a;
        for(size_t t = 0; t < LEN; t++)
            a.add(v[w]);

        size_t LEN2 = 64 * 8 / (a.GetBitWidth() == 0 ? 1 : a.GetBitWidth());

        for(size_t from = 0; from < LEN2; from++) {
            for(size_t to = from + 1; to <= LEN2; to++) {
                for(size_t match = 0; match < LEN2; match++) {

                    // LESS
                    a.Set(match, v[w] - 1);
                    size_t f = a.Query<LESS>(v[w], from, to);
                    a.Set(match, v[w]);
                    if(match >= from && match < to) {
                        assert(match == f);
                    }
                    else {
                        assert(f == -1);
                    }

                    if(to == 9 && match == 1)
                        printf("");

                    // FIND
                    a.Set(match, v[w]-1);
                    f = a.find_first(v[w]-1, from, to);
                    a.Set(match, v[w]);
                    if(match >= from && match < to) {
                        assert(match == f);
                    }
                    else {
                        assert(f == -1);
                    }

                    // MIN
                    int64_t val = 0;
                    a.Set(match, v[w]-1);
                    bool b = a.minimum(val, from, to);
                    a.Set(match, v[w]);
                    CHECK_EQUAL(true, b);
                    if(match >= from && match < to)
                        assert(val == v[w]-1);
                    else
                        assert(val == v[w]);

                    // MAX
                    a.Set(match, v[w]+1);
                    b = a.maximum(val, from, to);
                    a.Set(match, v[w]);
                    CHECK_EQUAL(true, b);
                    if(match >= from && match < to)
                        assert(val == v[w]+1);
                    else
                        assert(val == v[w]);

                }
            }

        }
        a.Destroy();
    }
}

TEST(Column_monkeytest2)
{
    const uint64_t ITER_PER_BITWIDTH = 16 * 1000 * TEST_DURATION * TEST_DURATION * TEST_DURATION;
    const uint64_t SEED = 123;

    VerifiedInteger a;
    Array res;

    srand(SEED);
    size_t current_bitwidth = 0;
    unsigned int trend = 5;

    for(current_bitwidth = 0; current_bitwidth < 65; current_bitwidth++) {
        for(size_t iter = 0; iter < ITER_PER_BITWIDTH; iter++) {

//          if(rand() % 10 == 0) printf("Input bitwidth around ~%d, , a.Size()=%d\n", (int)current_bitwidth, (int)a.Size());

            if (!(rand2() % (ITER_PER_BITWIDTH / 100))) {
                trend = (unsigned int)rand2() % 10;
                a.find_first(rand2(current_bitwidth));
                a.find_all(res, rand2(current_bitwidth));
                size_t start = rand2() % (a.Size() + 1);
                a.Sum(start, start + rand2() % (a.Size() + 1 - start));
                a.maximum(start, start + rand2() % (a.Size() + 1 - start));
                a.minimum(start, start + rand2() % (a.Size() + 1 - start));
            }

            if (rand2() % 10 > trend && a.Size() < ITER_PER_BITWIDTH / 100) {
                uint64_t l = rand2(current_bitwidth);
                if(rand2() % 2 == 0) {
                    // Insert
                    const size_t pos = rand2() % (a.Size() + 1);
                    a.Insert(pos, l);
                }
                else {
                    // Add
                    a.add(l);
                }
            }
            else if(a.Size() > 0) {
                // Delete
                const size_t i = rand2() % a.Size();
                a.Delete(i);
            }
        }
    }

    // Cleanup
    a.Destroy();
    res.Destroy();
}

#endif
<commit_msg>Unit tests<commit_after>#include "../testsettings.hpp"

#if TEST_DURATION > 0

#include "tightdb/column.hpp"
#include <UnitTest++.h>
#include <vector>
#include <algorithm>
#include "verified_integer.hpp"
#include "tightdb/query_conditions.hpp"

using namespace tightdb;

namespace {

uint64_t rand2(int bitwidth = 64)
{
    uint64_t i = (int64_t)rand() * (int64_t)rand() * (int64_t)rand() * (int64_t)rand() * (int64_t)rand();
    if(bitwidth < 64) {
        const uint64_t mask = ((1ULL << bitwidth) - 1ULL);
        i &= mask;
    }
    return i;
}

}

TEST(LESS)
{
    int64_t v[13] = {0, 1, 3, 15, 100, 30000, 1000000LL, 1000LL*1000LL*1000LL*1000LL, -15, -100, -30000, -1000000ULL, -1000ULL*1000LL*1000LL*1000LL};

    for (size_t w = 0; w < 13; w++) {
        const size_t LEN = 64 * 8; // to create at least 64 bytes of data (2 * 128-bit SSE chunks + 64 bit chunk before and after + some unaligned data before and after)
        Array a;
        for(size_t t = 0; t < LEN; t++)
            a.add(v[w]);

        size_t LEN2 = 64 * 8 / (a.GetBitWidth() == 0 ? 1 : a.GetBitWidth());

        for(size_t from = 0; from < 16*8 + 1; from++) {
            for(size_t to = from + 1; to <= LEN2; to++) {
                for(size_t match = 0; match < LEN2; match++) {

                    // LESS
                    a.Set(match, v[w] - 1);
                    size_t f = a.Query<LESS>(v[w], from, to);
                    a.Set(match, v[w]);
                    if(match >= from && match < to) {
                        assert(match == f);
                    }
                    else {
                        assert(f == -1);
                    }

                    // GREATER
                    a.Set(match, v[w] + 1);
                    f = a.Query<GREATER>(v[w], from, to);
                    a.Set(match, v[w]);
                    if(match >= from && match < to) {
                        assert(match == f);
                    }
                    else {
                        assert(f == -1);
                    }

                    if(to == 9 && match == 1)
                        printf("");

                    // FIND
                    a.Set(match, v[w]-1);
                    f = a.find_first(v[w]-1, from, to);
                    a.Set(match, v[w]);
                    if(match >= from && match < to) {
                        assert(match == f);
                    }
                    else {
                        assert(f == -1);
                    }

                    // MIN
                    int64_t val = 0;
                    a.Set(match, v[w]-1);
                    bool b = a.minimum(val, from, to);
                    a.Set(match, v[w]);
                    CHECK_EQUAL(true, b);
                    if(match >= from && match < to)
                        assert(val == v[w]-1);
                    else
                        assert(val == v[w]);

                    // MAX
                    a.Set(match, v[w]+1);
                    b = a.maximum(val, from, to);
                    a.Set(match, v[w]);
                    CHECK_EQUAL(true, b);
                    if(match >= from && match < to)
                        assert(val == v[w]+1);
                    else
                        assert(val == v[w]);

                }
            }

        }
        a.Destroy();
    }
}

TEST(Column_monkeytest2)
{
    const uint64_t ITER_PER_BITWIDTH = 16 * 1000 * TEST_DURATION * TEST_DURATION * TEST_DURATION;
    const uint64_t SEED = 123;

    VerifiedInteger a;
    Array res;

    srand(SEED);
    size_t current_bitwidth = 0;
    unsigned int trend = 5;

    for(current_bitwidth = 0; current_bitwidth < 65; current_bitwidth++) {
        for(size_t iter = 0; iter < ITER_PER_BITWIDTH; iter++) {

//          if(rand() % 10 == 0) printf("Input bitwidth around ~%d, , a.Size()=%d\n", (int)current_bitwidth, (int)a.Size());

            if (!(rand2() % (ITER_PER_BITWIDTH / 100))) {
                trend = (unsigned int)rand2() % 10;
                a.find_first(rand2(current_bitwidth));
                a.find_all(res, rand2(current_bitwidth));
                size_t start = rand2() % (a.Size() + 1);
                a.Sum(start, start + rand2() % (a.Size() + 1 - start));
                a.maximum(start, start + rand2() % (a.Size() + 1 - start));
                a.minimum(start, start + rand2() % (a.Size() + 1 - start));
            }

            if (rand2() % 10 > trend && a.Size() < ITER_PER_BITWIDTH / 100) {
                uint64_t l = rand2(current_bitwidth);
                if(rand2() % 2 == 0) {
                    // Insert
                    const size_t pos = rand2() % (a.Size() + 1);
                    a.Insert(pos, l);
                }
                else {
                    // Add
                    a.add(l);
                }
            }
            else if(a.Size() > 0) {
                // Delete
                const size_t i = rand2() % a.Size();
                a.Delete(i);
            }
        }
    }

    // Cleanup
    a.Destroy();
    res.Destroy();
}

#endif
<|endoftext|>


<commit_before>/**
 * \file wfbfpsdd_search.cc
 *
 *
 *
 * \author Ethan Burns
 * \date 2008-11-20
 */

#include <pthread.h>

#include <limits>
#include <iostream>
#include <vector>

#include "wbfpsdd_search.h"
#include "wbfpsdd/nblock_graph.h"
#include "wbfpsdd/nblock.h"
#include "util/thread.h"
#include "util/timer.h"
#include "projection.h"
#include "open_list.h"
#include "closed_list.h"

using namespace std;
using namespace WBFPSDD;

/**
 * Create a new PSDD Search thread.
 */
WBFPSDDSearch::WBFPSDDThread::WBFPSDDThread(NBlockGraph *graph,
					    WBFPSDDSearch *search)
	: graph(graph), search(search) {}

WBFPSDDSearch::WBFPSDDThread::~WBFPSDDThread() {}

/**
 * The thread work method for a PSDD search.
 */
void WBFPSDDSearch::WBFPSDDThread::run(void)
{
	vector<State *> *path;
	NBlock *n = NULL;

	do {
		n = graph->next_nblock(n);

		if ((search->weight * graph->get_f_min()) > search->bound.read())
			break;

		if (n) {
			exp_this_block = 0;
			path = search_nblock(n);

			if (path)
				search->set_path(path);
			ave_exp_per_nblock.add_val(exp_this_block);
		}

	} while(!search->done && n);

	search->done = true;
	graph->set_done();
}

fp_type WBFPSDDSearch::WBFPSDDThread::get_ave_exp_per_nblock(void)
{
	return ave_exp_per_nblock.read();
}

/**
 * Search a single NBlock.
 * \param n The NBlock.
 * \return NULL, or a path to a goal.
 */
vector<State *> *WBFPSDDSearch::WBFPSDDThread::search_nblock(NBlock *n)
{
	vector<State *> *path = NULL;

	while (!search->done && !n->open_fp.empty()) {
		if (exp_this_block > search->min_expansions
		    && n->open_fp.get_best_val() > graph->get_layer_value())
			break;

		if (search->weight * n->open_f.get_best_val() >= search->bound.read()) {
			n->open_f.prune();
			n->open_fp.prune();
			break;
		}

		State *s = n->open_fp.take();
		n->open_f.remove(s);

		if (s->get_f_prime() >= search->bound.read()) {
			n->open_fp.prune();
			n->open_f.prune();
			break;
		}

		if (search->weight * s->get_f() >= search->bound.read())
			continue;

		if (s->is_goal()) {
			path = s->get_path();
			break;
		}

		exp_this_block += 1;

		vector<State *> *children = search->expand(s);
		vector<State *>::iterator iter;
		for (iter = children->begin();
		     iter != children->end();
		     iter++) {
			unsigned int block = search->project->project(*iter);
			NBlock *b = graph->get_nblock(block);
			PQOpenList<State::PQOpsF> *next_open_f = &b->open_f;
			PQOpenList<State::PQOpsFPrime> *next_open_fp = &b->open_fp;
			ClosedList *next_closed = &graph->get_nblock(block)->closed;
			if (search->weight * (*iter)->get_f() >= search->bound.read()) {
				delete *iter;
				continue;
			}
			State *dup = next_closed->lookup(*iter);
			if (dup) {
				if (dup->get_g() > (*iter)->get_g()) {
					dup->update((*iter)->get_parent(),
						    (*iter)->get_g());
					if (dup->is_open()) {
						next_open_f->see_update(dup);
						next_open_fp->see_update(dup);
					} else {
						next_open_f->add(dup);
						next_open_fp->add(dup);
					}
				}
				delete *iter;
			} else {
				next_closed->add(*iter);
				if ((*iter)->is_goal()) {
					path = (*iter)->get_path();
					delete children;
					return path;
				}
				next_open_f->add(*iter);
				next_open_fp->add(*iter);
			}
		}
		delete children;

	}

	return path;
}

/**********************************************************************/

/**
 * Create a new Parallel Structured Duplicate Detection search.
 */
WBFPSDDSearch::WBFPSDDSearch(unsigned int n_threads, fp_type mult, unsigned int min_expansions)
	: bound(fp_infinity),
	  n_threads(n_threads),
	  project(NULL),
	  path(NULL),
	  graph(NULL),
	  min_expansions(min_expansions),
	  multiplier(mult)
{
	pthread_mutex_init(&path_mutex, NULL);
}

/**
 * Create a new Parallel Structured Duplicate Detection search with a
 * given bound.
 */
WBFPSDDSearch::WBFPSDDSearch(unsigned int n_threads, fp_type mult, unsigned int min_expansions, fp_type bound)
	: bound(bound),
	  n_threads(n_threads),
	  project(NULL),
	  path(NULL),
	  graph(NULL),
	  min_expansions(min_expansions),
	  multiplier(mult),
	  done(false)
{
	pthread_mutex_init(&path_mutex, NULL);
}

/**
 * Destructor.
 */
WBFPSDDSearch::~WBFPSDDSearch(void)
{
	if (graph)
		delete graph;
}

/**
 * Set the path to the goal.
 */
void WBFPSDDSearch::set_path(vector<State *> *p)
{
	pthread_mutex_lock(&path_mutex);
	assert(!p || p->at(0)->get_g() == p->at(0)->get_f());
	if (p && bound.read() >= p->at(0)->get_g()) {
		this->path = p;
		bound.set(p->at(0)->get_g());

		if ((weight * graph->get_f_min()) > p->at(0)->get_g())
			done = true;
	}
	pthread_mutex_unlock(&path_mutex);
}

/**
 * Test if there has been a path to the goal found yet.
 */
bool WBFPSDDSearch::path_found(void) const
{
	return path != NULL;
}

/**
 * Perform the search.
 */
vector<State *> *WBFPSDDSearch::search(State *initial)
{
	project = initial->get_domain()->get_projection();

	vector<WBFPSDDThread *> threads;
	vector<WBFPSDDThread *>::iterator iter;
	fp_type sum = 0.0;
	unsigned int num = 0;
	Timer t;

	t.start();
	graph = new NBlockGraph(project,
				n_threads,
				multiplier,
				initial);
	t.stop();

	weight = initial->get_domain()->get_heuristic()->get_weight();

	for (unsigned int i = 0; i < n_threads; i += 1) {
		WBFPSDDThread *t = new WBFPSDDThread(graph, this);
		threads.push_back(t);
		t->start();
	}

	for (iter = threads.begin(); iter != threads.end(); iter++) {
		(*iter)->join();

		fp_type ave = (*iter)->get_ave_exp_per_nblock();
		if (ave != 0.0) {
			sum += ave;
			num += 1;
		}

		delete *iter;
	}

	if (num == 0)
		cout << "expansions-per-nblock: -1" << endl;
	else
		cout << "expansions-per-nblock: " << sum / num << endl;

	cout << "nblock-graph-creation-time: " << t.get_wall_time() << endl;

	cout << "total-nblocks: " << project->get_num_nblocks() << endl;
	cout << "created-nblocks: " << graph->get_ncreated_nblocks() << endl;

	return path;
}

/**
 * Set the bound.
 */
void WBFPSDDSearch::set_bound(fp_type b)
{
	this->bound.set(b);
}
<commit_msg>Move pruning in wBFPSDD to be before we get the info from the node we may prune.<commit_after>/**
 * \file wfbfpsdd_search.cc
 *
 *
 *
 * \author Ethan Burns
 * \date 2008-11-20
 */

#include <pthread.h>

#include <limits>
#include <iostream>
#include <vector>

#include "wbfpsdd_search.h"
#include "wbfpsdd/nblock_graph.h"
#include "wbfpsdd/nblock.h"
#include "util/thread.h"
#include "util/timer.h"
#include "projection.h"
#include "open_list.h"
#include "closed_list.h"

using namespace std;
using namespace WBFPSDD;

/**
 * Create a new PSDD Search thread.
 */
WBFPSDDSearch::WBFPSDDThread::WBFPSDDThread(NBlockGraph *graph,
					    WBFPSDDSearch *search)
	: graph(graph), search(search) {}

WBFPSDDSearch::WBFPSDDThread::~WBFPSDDThread() {}

/**
 * The thread work method for a PSDD search.
 */
void WBFPSDDSearch::WBFPSDDThread::run(void)
{
	vector<State *> *path;
	NBlock *n = NULL;

	do {
		n = graph->next_nblock(n);

		if ((search->weight * graph->get_f_min()) > search->bound.read())
			break;

		if (n) {
			exp_this_block = 0;
			path = search_nblock(n);

			if (path)
				search->set_path(path);
			ave_exp_per_nblock.add_val(exp_this_block);
		}

	} while(!search->done && n);

	search->done = true;
	graph->set_done();
}

fp_type WBFPSDDSearch::WBFPSDDThread::get_ave_exp_per_nblock(void)
{
	return ave_exp_per_nblock.read();
}

/**
 * Search a single NBlock.
 * \param n The NBlock.
 * \return NULL, or a path to a goal.
 */
vector<State *> *WBFPSDDSearch::WBFPSDDThread::search_nblock(NBlock *n)
{
	vector<State *> *path = NULL;

	while (!search->done && !n->open_fp.empty()) {
		if (exp_this_block > search->min_expansions
		    && n->open_fp.get_best_val() > graph->get_layer_value())
			break;

		if (search->weight * n->open_f.get_best_val() >= search->bound.read()) {
			n->open_f.prune();
			n->open_fp.prune();
			break;
		}

		State *s = n->open_fp.take();
		n->open_f.remove(s);

		if (s->get_f_prime() >= search->bound.read()) {
			n->open_fp.prune();
			n->open_f.prune();
			break;
		}

		if (search->weight * s->get_f() >= search->bound.read())
			continue;

		if (s->is_goal()) {
			path = s->get_path();
			break;
		}

		exp_this_block += 1;

		vector<State *> *children = search->expand(s);
		vector<State *>::iterator iter;
		for (iter = children->begin();
		     iter != children->end();
		     iter++) {
			if (search->weight * (*iter)->get_f() >= search->bound.read()) {
				delete *iter;
				continue;
			}
			unsigned int block = search->project->project(*iter);
			NBlock *b = graph->get_nblock(block);
			PQOpenList<State::PQOpsF> *next_open_f = &b->open_f;
			PQOpenList<State::PQOpsFPrime> *next_open_fp = &b->open_fp;
			ClosedList *next_closed = &graph->get_nblock(block)->closed;
			State *dup = next_closed->lookup(*iter);
			if (dup) {
				if (dup->get_g() > (*iter)->get_g()) {
					dup->update((*iter)->get_parent(),
						    (*iter)->get_g());
					if (dup->is_open()) {
						next_open_f->see_update(dup);
						next_open_fp->see_update(dup);
					} else {
						next_open_f->add(dup);
						next_open_fp->add(dup);
					}
				}
				delete *iter;
			} else {
				next_closed->add(*iter);
				if ((*iter)->is_goal()) {
					path = (*iter)->get_path();
					delete children;
					return path;
				}
				next_open_f->add(*iter);
				next_open_fp->add(*iter);
			}
		}
		delete children;

	}

	return path;
}

/**********************************************************************/

/**
 * Create a new Parallel Structured Duplicate Detection search.
 */
WBFPSDDSearch::WBFPSDDSearch(unsigned int n_threads, fp_type mult, unsigned int min_expansions)
	: bound(fp_infinity),
	  n_threads(n_threads),
	  project(NULL),
	  path(NULL),
	  graph(NULL),
	  min_expansions(min_expansions),
	  multiplier(mult)
{
	pthread_mutex_init(&path_mutex, NULL);
}

/**
 * Create a new Parallel Structured Duplicate Detection search with a
 * given bound.
 */
WBFPSDDSearch::WBFPSDDSearch(unsigned int n_threads, fp_type mult, unsigned int min_expansions, fp_type bound)
	: bound(bound),
	  n_threads(n_threads),
	  project(NULL),
	  path(NULL),
	  graph(NULL),
	  min_expansions(min_expansions),
	  multiplier(mult),
	  done(false)
{
	pthread_mutex_init(&path_mutex, NULL);
}

/**
 * Destructor.
 */
WBFPSDDSearch::~WBFPSDDSearch(void)
{
	if (graph)
		delete graph;
}

/**
 * Set the path to the goal.
 */
void WBFPSDDSearch::set_path(vector<State *> *p)
{
	pthread_mutex_lock(&path_mutex);
	assert(!p || p->at(0)->get_g() == p->at(0)->get_f());
	if (p && bound.read() >= p->at(0)->get_g()) {
		this->path = p;
		bound.set(p->at(0)->get_g());

		if ((weight * graph->get_f_min()) > p->at(0)->get_g())
			done = true;
	}
	pthread_mutex_unlock(&path_mutex);
}

/**
 * Test if there has been a path to the goal found yet.
 */
bool WBFPSDDSearch::path_found(void) const
{
	return path != NULL;
}

/**
 * Perform the search.
 */
vector<State *> *WBFPSDDSearch::search(State *initial)
{
	project = initial->get_domain()->get_projection();

	vector<WBFPSDDThread *> threads;
	vector<WBFPSDDThread *>::iterator iter;
	fp_type sum = 0.0;
	unsigned int num = 0;
	Timer t;

	t.start();
	graph = new NBlockGraph(project,
				n_threads,
				multiplier,
				initial);
	t.stop();

	weight = initial->get_domain()->get_heuristic()->get_weight();

	for (unsigned int i = 0; i < n_threads; i += 1) {
		WBFPSDDThread *t = new WBFPSDDThread(graph, this);
		threads.push_back(t);
		t->start();
	}

	for (iter = threads.begin(); iter != threads.end(); iter++) {
		(*iter)->join();

		fp_type ave = (*iter)->get_ave_exp_per_nblock();
		if (ave != 0.0) {
			sum += ave;
			num += 1;
		}

		delete *iter;
	}

	if (num == 0)
		cout << "expansions-per-nblock: -1" << endl;
	else
		cout << "expansions-per-nblock: " << sum / num << endl;

	cout << "nblock-graph-creation-time: " << t.get_wall_time() << endl;

	cout << "total-nblocks: " << project->get_num_nblocks() << endl;
	cout << "created-nblocks: " << graph->get_ncreated_nblocks() << endl;

	return path;
}

/**
 * Set the bound.
 */
void WBFPSDDSearch::set_bound(fp_type b)
{
	this->bound.set(b);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "thrift/lib/cpp2/transport/rsocket/client/RSClientConnection.h"

#include <folly/io/async/EventBase.h>
#include <rsocket/framing/FramedDuplexConnection.h>
#include <rsocket/transports/tcp/TcpDuplexConnection.h>
#include <thrift/lib/cpp/async/TAsyncSocket.h>
#include <thrift/lib/cpp/transport/TTransportException.h>

#include <unordered_map>

namespace apache {
namespace thrift {

using namespace rsocket;
using apache::thrift::transport::TTransportException;

class RSConnectionStatus : public rsocket::RSocketConnectionEvents {
 public:
  void setCloseCallback(ThriftClient* client, CloseCallback* ccb) {
    if (ccb == nullptr) {
      closeCallbacks_.erase(client);
    } else {
      closeCallbacks_[client] = ccb;
    }
  }

  bool isConnected() const {
    return isConnected_;
  }

 private:
  void onConnected() override {
    isConnected_ = true;
  }

  void onDisconnected(const folly::exception_wrapper&) override {
    closed();
  }

  void onClosed(const folly::exception_wrapper&) override {
    closed();
  }

  void closed() {
    if (isConnected_) {
      isConnected_ = false;
      for (auto& cb : closeCallbacks_) {
        cb.second->channelClosed();
      }
      closeCallbacks_.clear();
    }
  }

  bool isConnected_{false};

  // A map of all registered CloseCallback objects keyed by the
  // ThriftClient objects that registered the callback.
  std::unordered_map<ThriftClient*, CloseCallback*> closeCallbacks_;
};

RSClientConnection::RSClientConnection(
    apache::thrift::async::TAsyncTransport::UniquePtr socket,
    bool isSecure)
    : evb_(socket->getEventBase()),
      isSecure_(isSecure),
      connectionStatus_(std::make_shared<RSConnectionStatus>()) {
  rsRequester_ =
      std::make_shared<RSRequester>(std::move(socket), evb_, connectionStatus_);

  channel_ =
      std::make_shared<RSClientThriftChannel>(rsRequester_, counters_, evb_);
}

RSClientConnection::~RSClientConnection() {
  if (rsRequester_) {
    evb_->runInEventBaseThread(
        [rsRequester = std::move(rsRequester_)]() { rsRequester->closeNow(); });
  }
}

std::shared_ptr<ThriftChannelIf> RSClientConnection::getChannel(
    RequestRpcMetadata*) {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  if (!channel_ || !connectionStatus_->isConnected()) {
    throw TTransportException(
        TTransportException::NOT_OPEN, "Connection is not open");
  }
  return channel_;
}

void RSClientConnection::setMaxPendingRequests(uint32_t count) {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  counters_.setMaxPendingRequests(count);
}

folly::EventBase* RSClientConnection::getEventBase() const {
  return evb_;
}

apache::thrift::async::TAsyncTransport* FOLLY_NULLABLE
RSClientConnection::getTransport() {
  DCHECK(!evb_ || evb_->isInEventBaseThread());
  if (rsRequester_) {
    DuplexConnection* connection = rsRequester_->getConnection();
    if (!connection) {
      LOG_EVERY_N(ERROR, 100)
          << "Connection is already closed. May be protocol mismatch x 100";
      channel_.reset();
      rsRequester_.reset();
      return nullptr;
    }
    if (auto framedConnection =
            dynamic_cast<FramedDuplexConnection*>(connection)) {
      connection = framedConnection->getConnection();
    }
    auto* tcpConnection = dynamic_cast<TcpDuplexConnection*>(connection);
    CHECK_NOTNULL(tcpConnection);
    return dynamic_cast<apache::thrift::async::TAsyncTransport*>(
        tcpConnection->getTransport());
  }
  return nullptr;
}

bool RSClientConnection::good() {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  auto const socket = getTransport();
  return channel_ && socket && socket->good();
}

ClientChannel::SaturationStatus RSClientConnection::getSaturationStatus() {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  return ClientChannel::SaturationStatus(
      counters_.getPendingRequests(), counters_.getMaxPendingRequests());
}

void RSClientConnection::attachEventBase(folly::EventBase* evb) {
  DCHECK(evb->isInEventBaseThread());
  auto transport = getTransport();
  if (transport) {
    transport->attachEventBase(evb);
  }
  if (channel_) {
    channel_->attachEventBase(evb);
  }
  if (rsRequester_) {
    rsRequester_->attachEventBase(evb);
  }
  evb_ = evb;
}

void RSClientConnection::detachEventBase() {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  auto transport = getTransport();
  if (transport) {
    transport->detachEventBase();
  }
  if (channel_) {
    channel_->detachEventBase();
  }
  if (rsRequester_) {
    rsRequester_->detachEventBase();
  }
  evb_ = nullptr;
}

bool RSClientConnection::isDetachable() {
  auto transport = getTransport();
  bool result = evb_ == nullptr || transport == nullptr ||
      channel_ == nullptr || rsRequester_ == nullptr ||
      (counters_.getPendingRequests() == 0 && transport->isDetachable() &&
       channel_->isDetachable() && rsRequester_->isDetachable());
  return result;
}

bool RSClientConnection::isSecurityActive() {
  return isSecure_;
}

uint32_t RSClientConnection::getTimeout() {
  // TODO: Need to inspect this functionality for RSocket
  return timeout_.count();
}

void RSClientConnection::setTimeout(uint32_t timeoutMs) {
  // TODO: Need to inspect this functionality for RSocket
  timeout_ = std::chrono::milliseconds(timeoutMs);
}

void RSClientConnection::closeNow() {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  if (rsRequester_) {
    channel_.reset();
    rsRequester_->closeNow();
    rsRequester_.reset();
  }
}

CLIENT_TYPE RSClientConnection::getClientType() {
  // TODO: Should we use this value?
  return THRIFT_HTTP_CLIENT_TYPE;
}

void RSClientConnection::setCloseCallback(
    ThriftClient* client,
    CloseCallback* cb) {
  connectionStatus_->setCloseCallback(client, cb);
}

} // namespace thrift
} // namespace apache
<commit_msg>Safely destroying RSClientConnection with detached EventBase<commit_after>/*
 * Copyright 2017-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "thrift/lib/cpp2/transport/rsocket/client/RSClientConnection.h"

#include <folly/io/async/EventBase.h>
#include <rsocket/framing/FramedDuplexConnection.h>
#include <rsocket/transports/tcp/TcpDuplexConnection.h>
#include <thrift/lib/cpp/async/TAsyncSocket.h>
#include <thrift/lib/cpp/transport/TTransportException.h>

#include <unordered_map>

namespace apache {
namespace thrift {

using namespace rsocket;
using apache::thrift::transport::TTransportException;

class RSConnectionStatus : public rsocket::RSocketConnectionEvents {
 public:
  void setCloseCallback(ThriftClient* client, CloseCallback* ccb) {
    if (ccb == nullptr) {
      closeCallbacks_.erase(client);
    } else {
      closeCallbacks_[client] = ccb;
    }
  }

  bool isConnected() const {
    return isConnected_;
  }

 private:
  void onConnected() override {
    isConnected_ = true;
  }

  void onDisconnected(const folly::exception_wrapper&) override {
    closed();
  }

  void onClosed(const folly::exception_wrapper&) override {
    closed();
  }

  void closed() {
    if (isConnected_) {
      isConnected_ = false;
      for (auto& cb : closeCallbacks_) {
        cb.second->channelClosed();
      }
      closeCallbacks_.clear();
    }
  }

  bool isConnected_{false};

  // A map of all registered CloseCallback objects keyed by the
  // ThriftClient objects that registered the callback.
  std::unordered_map<ThriftClient*, CloseCallback*> closeCallbacks_;
};

RSClientConnection::RSClientConnection(
    apache::thrift::async::TAsyncTransport::UniquePtr socket,
    bool isSecure)
    : evb_(socket->getEventBase()),
      isSecure_(isSecure),
      connectionStatus_(std::make_shared<RSConnectionStatus>()) {
  rsRequester_ =
      std::make_shared<RSRequester>(std::move(socket), evb_, connectionStatus_);

  channel_ =
      std::make_shared<RSClientThriftChannel>(rsRequester_, counters_, evb_);
}

RSClientConnection::~RSClientConnection() {
  if (rsRequester_) {
    if (evb_ && !evb_->isInEventBaseThread()) {
      evb_->runInEventBaseThread([rsRequester = std::move(rsRequester_)]() {
        rsRequester->closeNow();
      });
    } else {
      // If evb_ is missing, this function will attach the current event base
      // instead of the missing one
      closeNow();
    }
  }
}

std::shared_ptr<ThriftChannelIf> RSClientConnection::getChannel(
    RequestRpcMetadata*) {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  if (!channel_ || !connectionStatus_->isConnected()) {
    throw TTransportException(
        TTransportException::NOT_OPEN, "Connection is not open");
  }
  return channel_;
}

void RSClientConnection::setMaxPendingRequests(uint32_t count) {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  counters_.setMaxPendingRequests(count);
}

folly::EventBase* RSClientConnection::getEventBase() const {
  return evb_;
}

apache::thrift::async::TAsyncTransport* FOLLY_NULLABLE
RSClientConnection::getTransport() {
  DCHECK(!evb_ || evb_->isInEventBaseThread());
  if (rsRequester_) {
    DuplexConnection* connection = rsRequester_->getConnection();
    if (!connection) {
      LOG_EVERY_N(ERROR, 100)
          << "Connection is already closed. May be protocol mismatch x 100";
      channel_.reset();
      rsRequester_.reset();
      return nullptr;
    }
    if (auto framedConnection =
            dynamic_cast<FramedDuplexConnection*>(connection)) {
      connection = framedConnection->getConnection();
    }
    auto* tcpConnection = dynamic_cast<TcpDuplexConnection*>(connection);
    CHECK_NOTNULL(tcpConnection);
    return dynamic_cast<apache::thrift::async::TAsyncTransport*>(
        tcpConnection->getTransport());
  }
  return nullptr;
}

bool RSClientConnection::good() {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  auto const socket = getTransport();
  return channel_ && socket && socket->good();
}

ClientChannel::SaturationStatus RSClientConnection::getSaturationStatus() {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  return ClientChannel::SaturationStatus(
      counters_.getPendingRequests(), counters_.getMaxPendingRequests());
}

void RSClientConnection::attachEventBase(folly::EventBase* evb) {
  DCHECK(evb->isInEventBaseThread());
  auto transport = getTransport();
  if (transport) {
    transport->attachEventBase(evb);
  }
  if (channel_) {
    channel_->attachEventBase(evb);
  }
  if (rsRequester_) {
    rsRequester_->attachEventBase(evb);
  }
  evb_ = evb;
}

void RSClientConnection::detachEventBase() {
  DCHECK(evb_ && evb_->isInEventBaseThread());
  auto transport = getTransport();
  if (transport) {
    transport->detachEventBase();
  }
  if (channel_) {
    channel_->detachEventBase();
  }
  if (rsRequester_) {
    rsRequester_->detachEventBase();
  }
  evb_ = nullptr;
}

bool RSClientConnection::isDetachable() {
  auto transport = getTransport();
  bool result = evb_ == nullptr || transport == nullptr ||
      channel_ == nullptr || rsRequester_ == nullptr ||
      (counters_.getPendingRequests() == 0 && transport->isDetachable() &&
       channel_->isDetachable() && rsRequester_->isDetachable());
  return result;
}

bool RSClientConnection::isSecurityActive() {
  return isSecure_;
}

uint32_t RSClientConnection::getTimeout() {
  // TODO: Need to inspect this functionality for RSocket
  return timeout_.count();
}

void RSClientConnection::setTimeout(uint32_t timeoutMs) {
  // TODO: Need to inspect this functionality for RSocket
  timeout_ = std::chrono::milliseconds(timeoutMs);
}

void RSClientConnection::closeNow() {
  DCHECK(!evb_ || evb_->isInEventBaseThread());
  if (rsRequester_) {
    channel_.reset();
    if (!evb_) {
      // Add current event base instead of the missing one.
      LOG(ERROR) << "Closing RSClientConnection with missing EventBase";
      attachEventBase(folly::EventBaseManager::get()->getEventBase());
    }
    rsRequester_->closeNow();
    rsRequester_.reset();
  }
}

CLIENT_TYPE RSClientConnection::getClientType() {
  // TODO: Should we use this value?
  return THRIFT_HTTP_CLIENT_TYPE;
}

void RSClientConnection::setCloseCallback(
    ThriftClient* client,
    CloseCallback* cb) {
  connectionStatus_->setCloseCallback(client, cb);
}

} // namespace thrift
} // namespace apache
<|endoftext|>


<commit_before>#include "../stdafx.h"
#include "../Exception.h"
#include "../Util.h"
#include "../Primitive/Primitive.h"
#include "../Tracer/Intersection.h"
#include "../Tracer/Ray.h"
#include "KDTree.h"
#include "KDTreeNode.h"
#include "Scene.h"

namespace SPTracer
{
	Scene::Scene()
	{
	}

	Scene::~Scene()
	{
	}

	void Scene::BuildKdTree()
	{
		// move primitives vector, because it will not be used in the future
		kdTree_ = std::make_unique<KdTree>(std::move(primitives_));
	}

	bool Scene::Intersect(const Ray& ray, Intersection& intersection) const
	{
		// ray inverted direction
		const Vec3 invDirection = 1 / ray.direction;

		// find the first box that ray intersects
		float tnear, tfar;
		const KdTreeNode* node = FindFirstIntersection(ray, invDirection, tnear, tfar);
		if (!node)
		{
			// no intersection with scene
			return false;
		}

		// set initial intersection distance to max possible,
		// so that any intersection will be closer than that
		intersection.distance = std::numeric_limits<float>::max();

		Intersection newIntersection;

		// find intersection with primitive
		while (true)
		{
			// find intersections with primitives in the node
			for (const auto& p : node->primitives())
			{
				// find new intersection
				bool success = p->Intersect(ray, newIntersection);

				// check if new intersection is closer
				if (success && (newIntersection.distance < intersection.distance) && (newIntersection.distance <= tfar))
				{
					intersection = newIntersection;
					intersection.primitive = p.get();
				}
			}

			// check if intersection was found
			if (intersection.distance < std::numeric_limits<float>::max())
			{
				return true;
			}

			// Intersection was not found,
			// get the node where ray travels next.
			node = FindNextIntersection(node, ray, invDirection, tnear, tfar);
			if (node == nullptr)
			{
				// no next node - no intersection
				return false;
			}
		}

		return false;
	}

	const KdTreeNode* Scene::FindFirstIntersection(const Ray& ray, const Vec3& invDirection, float& tnear, float& tfar) const
	{
		// start with root node
		const KdTreeNode* node = &kdTree_->rootNode();

		// check if ray intersects the scene
		if (!node->box().Intersect(ray, invDirection, tnear, tfar))
		{
			return nullptr;
		}

		// find the first box that ray intersects
		while (true)
		{
			// check if node is leaf
			if (node->isLeaf())
			{
				// the smallest first box interseced by the ray is found
				return node;
			}

			// test intersection with left sub-box
			float tnearLeft, tfarLeft;
			bool left = node->left().box().Intersect(ray, invDirection, tnearLeft, tfarLeft);

			// test intersection with right sub-box
			float tnearRight, tfarRight;
			bool right = node->right().box().Intersect(ray, invDirection, tnearRight, tfarRight);

			// check what sub-boxes were intersected
			if (left && right)
			{
				// both sub-boxes were intersected
				if (std::abs(tnearLeft - tnearRight) < Util::Eps)
				{
					// special case when ray hits exactly between the sub-boxes
					// choose the sub-box in which far intersection point is further
					if (tfarLeft > tfarRight)
					{
						// select left sub-box
						right = false;
					}
					else
					{
						// select right sub-box
						left = false;
					}
				}
				else if (tnearLeft < tnearRight)
				{
					// select left sub-box
					right = false;
				}
				else
				{
					// select right sub-box
					left = false;
				}
			}

			if (left)
			{
				// select left sub-box
				node = &node->left();
				tnear = tnearLeft;
				tfar = tfarLeft;
			}
			else
			{
				// select right sub-box
				node = &node->right();
				tnear = tnearRight;
				tfar = tfarRight;
			}
		}

		// should never get here
		throw Exception("Somehow escaped infinite loop in Scene::FindFirstIntersection");
	}

	const KdTreeNode* Scene::FindNextIntersection(const KdTreeNode* node, const Ray& ray, const Vec3& invDirection, float& tnear, float& tfar) const
	{
		// get the far point of intersection
		Vec3 far = ray.origin + tfar * ray.direction;

		// store original tfar to avoid infinite loop between two neighbours
		float tfarOriginal = tfar;

		// set initial value for tnear equal to tfar
		tnear = tfar;

		// next node
		KdTreeNode* nextNode = nullptr;

		// check all dimensions
		for (size_t i = 0; i < 3; ++i)
		{
			int face = -1;
			if (std::abs(far[i] - node->box().min()[i]) < Util::Eps)
			{
				// left plane in the current dimension
				face = i * 2;
			}
			else if (std::abs(far[i] - node->box().max()[i]) < Util::Eps)
			{
				// right plane in the current dimension
				face = i * 2 + 1;
			}

			if (face == -1)
			{
				// no faces
				continue;
			}

			// check if intersection point lies on any of the neighbour cells
			for (const auto& n : node->neighbours()[face])
			{
				bool found = true;
				for (size_t j = 0; j < 3; ++j)
				{
					// skip current dimension
					if (i == j)
					{
						continue;
					}

					if ((far[j] < node->box().min()[j]) || (far[j] > node->box().max()[j]))
					{
						found = false;
						break;
					}
				}

				// check if neighbour was found
				if (found)
				{
					// intersect ray with neigbour
					float tnearCandidate, tfarCandidate;
					if (!n->box().Intersect(ray, invDirection, tnearCandidate, tfarCandidate))
					{
						// some mistake, no intersection
						continue;
					}

					// the first check is needed to select the right neighbour if ray hits
					// exactly in between two neighbours
					// the second check is needed to ensure that the selected neighbour near
					// intersection matches the original box far intersection
					if (((tfarCandidate - tnearCandidate) > (tfar - tnear)) && (std::abs(tnearCandidate - tfarOriginal) < Util::Eps))
					{
						// store found neighbour
						nextNode = n.get();
						tnear = tnearCandidate;
						tfar = tfarCandidate;
					}
				}
			}
		}

		return nextNode;
	}

}
<commit_msg>Code refactoring<commit_after>#include "../stdafx.h"
#include "../Exception.h"
#include "../Util.h"
#include "../Primitive/Primitive.h"
#include "../Tracer/Intersection.h"
#include "../Tracer/Ray.h"
#include "KDTree.h"
#include "KDTreeNode.h"
#include "Scene.h"

namespace SPTracer
{
	Scene::Scene()
	{
	}

	Scene::~Scene()
	{
	}

	void Scene::BuildKdTree()
	{
		// move primitives vector, because it will not be used in the future
		kdTree_ = std::make_unique<KdTree>(std::move(primitives_));
	}

	bool Scene::Intersect(const Ray& ray, Intersection& intersection) const
	{
		// ray inverted direction
		const Vec3 invDirection = 1 / ray.direction;

		// find the first box that ray intersects
		float tnear, tfar;
		const KdTreeNode* node = FindFirstIntersection(ray, invDirection, tnear, tfar);
		if (!node)
		{
			// no intersection with scene
			return false;
		}

		// set initial intersection distance to max possible,
		// so that any intersection will be closer than that
		intersection.distance = std::numeric_limits<float>::max();

		Intersection newIntersection;

		// find intersection with primitive
		while (true)
		{
			// find intersections with primitives in the node
			for (const auto& p : node->primitives())
			{
				// find new intersection
				bool success = p->Intersect(ray, newIntersection);

				// check if new intersection is closer
				if (success && (newIntersection.distance < intersection.distance) && (newIntersection.distance <= tfar))
				{
					intersection = newIntersection;
					intersection.primitive = p.get();
				}
			}

			// check if intersection was found
			if (intersection.distance < std::numeric_limits<float>::max())
			{
				return true;
			}

			// Intersection was not found,
			// get the node where ray travels next.
			node = FindNextIntersection(node, ray, invDirection, tnear, tfar);
			if (node == nullptr)
			{
				// no next node - no intersection
				return false;
			}
		}

		return false;
	}

	const KdTreeNode* Scene::FindFirstIntersection(const Ray& ray, const Vec3& invDirection, float& tnear, float& tfar) const
	{
		// start with root node
		const KdTreeNode* node = &kdTree_->rootNode();

		// check if ray intersects the scene
		if (!node->box().Intersect(ray, invDirection, tnear, tfar))
		{
			return nullptr;
		}

		// find the first box that ray intersects
		while (true)
		{
			// check if node is leaf
			if (node->isLeaf())
			{
				// the smallest first box interseced by the ray is found
				return node;
			}

			// test intersection with left sub-box
			float tnearLeft, tfarLeft;
			bool left = node->left().box().Intersect(ray, invDirection, tnearLeft, tfarLeft);

			// test intersection with right sub-box
			float tnearRight, tfarRight;
			bool right = node->right().box().Intersect(ray, invDirection, tnearRight, tfarRight);

			// check what sub-boxes were intersected
			if (left && right)
			{
				// both sub-boxes were intersected
				if (std::abs(tnearLeft - tnearRight) < Util::Eps)
				{
					// special case when ray hits exactly between the sub-boxes
					// choose the sub-box in which far intersection point is further
					if (tfarLeft > tfarRight)
					{
						// select left sub-box
						right = false;
					}
					else
					{
						// select right sub-box
						left = false;
					}
				}
				else if (tnearLeft < tnearRight)
				{
					// select left sub-box
					right = false;
				}
				else
				{
					// select right sub-box
					left = false;
				}
			}

			if (left)
			{
				// select left sub-box
				node = &node->left();
				tnear = tnearLeft;
				tfar = tfarLeft;
			}
			else
			{
				// select right sub-box
				node = &node->right();
				tnear = tnearRight;
				tfar = tfarRight;
			}
		}

		// should never get here
		throw Exception("Somehow escaped infinite loop in Scene::FindFirstIntersection");
	}

	const KdTreeNode* Scene::FindNextIntersection(const KdTreeNode* node, const Ray& ray, const Vec3& invDirection, float& tnear, float& tfar) const
	{
		// get the far point of intersection
		Vec3 far = ray.origin + tfar * ray.direction;

		// store original tfar to avoid infinite loop between two neighbours
		float tfarOriginal = tfar;

		// set initial value for tnear equal to tfar
		tnear = tfar;

		// next node
		KdTreeNode* nextNode = nullptr;

		// check all dimensions
		for (int i = 0; i < 3; ++i)
		{
			int face = -1;
			if (std::abs(far[i] - node->box().min()[i]) < Util::Eps)
			{
				// left plane in the current dimension
				face = i * 2;
			}
			else if (std::abs(far[i] - node->box().max()[i]) < Util::Eps)
			{
				// right plane in the current dimension
				face = i * 2 + 1;
			}

			if (face == -1)
			{
				// no faces
				continue;
			}

			// check if intersection point lies on any of the neighbour cells
			for (const auto& n : node->neighbours()[face])
			{
				bool found = true;
				for (size_t j = 0; j < 3; ++j)
				{
					// skip current dimension
					if (i == j)
					{
						continue;
					}

					if ((far[j] < node->box().min()[j]) || (far[j] > node->box().max()[j]))
					{
						found = false;
						break;
					}
				}

				// check if neighbour was found
				if (found)
				{
					// intersect ray with neigbour
					float tnearCandidate, tfarCandidate;
					if (!n->box().Intersect(ray, invDirection, tnearCandidate, tfarCandidate))
					{
						// some mistake, no intersection
						continue;
					}

					// the first check is needed to select the right neighbour if ray hits
					// exactly in between two neighbours
					// the second check is needed to ensure that the selected neighbour near
					// intersection matches the original box far intersection
					if (((tfarCandidate - tnearCandidate) > (tfar - tnear)) && (std::abs(tnearCandidate - tfarOriginal) < Util::Eps))
					{
						// store found neighbour
						nextNode = n.get();
						tnear = tnearCandidate;
						tfar = tfarCandidate;
					}
				}
			}
		}

		return nextNode;
	}

}
<|endoftext|>