<commit_before>//
// OCCAM
//
// Copyright (c) 2011-2018, SRI International
//
//  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of SRI International nor the names of its contributors may
//   be used to endorse or promote products derived from this software without
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

/**
 * Intra-module specialization.
 **/

#include "llvm/Pass.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/IR/CallSite.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
//#include "llvm/Transforms/IPO/PassManagerBuilder.h"

#include "SpecializationTable.h"
#include "Specializer.h"
/* here specialization policies */
#include "AggressiveSpecPolicy.h"
#include "RecursiveGuardSpecPolicy.h"

using namespace llvm;
using namespace previrt;

static cl::opt<bool>
OptSpecialized("Ppeval-opt", cl::Hidden,
	       cl::init(false),
	       cl::desc("Optimize new specialized functions"));

static cl::opt<SpecializationPolicyType>
SpecPolicy("Ppeval-policy",
	   cl::desc("Intra-module specialization policy"),
	   cl::values
	   (clEnumValN (NOSPECIALIZE, "nospecialize",
			"Skip intra-module specialization"),
	    clEnumValN (AGGRESSIVE, "aggressive",
			"Specialize always if some constant argument"),
	    clEnumValN (NONRECURSIVE_WITH_AGGRESSIVE, "nonrec-aggressive",
			"aggressive + non-recursive function")),
	   cl::init(NONRECURSIVE_WITH_AGGRESSIVE));

namespace previrt
{

/**
   Return true if any callsite in f is specialized using policy.
**/
static bool trySpecializeFunction(Function* f, SpecializationTable& table,
				  SpecializationPolicy* policy,
				  std::vector<Function*>& to_add) {

  bool modified = false;

  for (BasicBlock& bb: *f) {
    for (Instruction& I: bb) {

      Instruction* ci = dyn_cast<CallInst>(&I);
      if (!ci) ci = dyn_cast<InvokeInst>(&I);
      if (!ci) continue;
      CallSite call(ci);

      Function* callee = call.getCalledFunction();
      if (!callee) {
	continue;
      }

      if (callee->isDeclaration() || callee->isVarArg()) {
        continue;
      }

      if (callee->hasFnAttribute(Attribute::NoInline) ||
	  callee->hasFnAttribute(Attribute::OptimizeNone)) {
        continue;
      }

      // specScheme[i] = nullptr if the i-th parameter of the callsite cannot be specialized.
      //                 c       if the i-th parameter of the callsite is a constant c
      std::vector<Value*> specScheme;
      bool specialize = policy->specializeOn(call, specScheme);
      if (!specialize) {
        continue;
      }

      // == BEGIN DEBUGGING =============================================
      #if 0
      errs() << "Specializing call to '" << callee->getName()
          << "' in function '" << f->getName() << "' on arguments [";
      for (unsigned int i = 0, cnt = 0; i < callee->arg_size(); ++i) {
        if (specScheme[i] != NULL) {
          if (cnt++ != 0)
            errs() << ",";
          Value* v = call.getInstruction()->getOperand(i);
          if (GlobalValue* gv = dyn_cast<GlobalValue>(v)) {
            errs() << i << "=(@" << gv->getName() << ")";
          } else {
            errs() << i << "=(" << *call.getInstruction()->getOperand(i) << ")";
          }
        }
      }
      errs() << "]\n";
      #endif
      // == END DEBUGGING ===============================================

      // --- build a specialized function if specScheme is more
      //     refined than all existing specialized versions.
      Function* specializedVersion = nullptr;
      std::vector<const SpecializationTable::Specialization*> versions;
      table.getSpecializations(callee, specScheme, versions);
      for (std::vector<const SpecializationTable::Specialization*>::iterator i =
          versions.begin(), e = versions.end(); i != e; ++i) {
        if (SpecializationTable::Specialization::refines(specScheme, (*i)->args)) {
          specializedVersion = (*i)->handle;
          break;
        }
      }

      if (!specializedVersion) {
        specializedVersion = specializeFunction(callee, specScheme);
        if(!specializedVersion) {
	  continue;
	}
        table.addSpecialization(callee, specScheme, specializedVersion);
        to_add.push_back(specializedVersion);
      }

      // -- build the specialized callsite
      const unsigned int specialized_arg_count = specializedVersion->arg_size();
      std::vector<unsigned> argPerm;
      argPerm.reserve(specialized_arg_count);
      for (unsigned from = 0; from < callee->arg_size(); from++) {
        if (!specScheme[from])
          argPerm.push_back(from);
      }
      assert(specialized_arg_count == argPerm.size());

      Instruction* newInst = specializeCallSite(&I, specializedVersion, argPerm);
      llvm::ReplaceInstWithInst(&I, newInst);

      modified = true;
    }
  }

  return modified;
}

/* Intra-module specialization */
class SpecializerPass : public llvm::ModulePass {
private:
  bool optimize;

public:
  static char ID;

  SpecializerPass(bool);
  virtual ~SpecializerPass();
  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const;
  virtual bool runOnModule(llvm::Module &M);
  virtual llvm::StringRef getPassName() const {
    return "Specializer";
  }
};

bool SpecializerPass::runOnModule(Module &M) {

  // -- Create the specialization policy. Bail out if no policy.
  SpecializationPolicy* policy = nullptr;
  switch (SpecPolicy) {
    case NOSPECIALIZE:
      return false;
    case AGGRESSIVE:
      policy = new AggressiveSpecPolicy();
      break;
    case NONRECURSIVE_WITH_AGGRESSIVE: {
      SpecializationPolicy* subpolicy = new AggressiveSpecPolicy();
      CallGraph& cg = getAnalysis<CallGraphWrapperPass>().getCallGraph();
      policy = new RecursiveGuardSpecPolicy(subpolicy, cg);
      break;
    }
  }

  // -- Specialize functions defined in M
  std::vector<Function*> to_add;
  SpecializationTable table(&M);
  bool modified = false;
  for (auto &f: M) {
    if(f.isDeclaration()) continue;
    modified |= trySpecializeFunction(&f, table, policy, to_add);
  }

  // -- Optimize new function and add it into the module
  llvm::legacy::FunctionPassManager* optimizer = nullptr;
  if (optimize) {
    optimizer = new llvm::legacy::FunctionPassManager(&M);
    //PassManagerBuilder builder;
    //builder.OptLevel = 3;
    //builder.populateFunctionPassManager(*optimizer);
  }

  while (!to_add.empty()) {
    Function* f = to_add.back();
    to_add.pop_back();
    if (f->getParent() == &M  || f->isDeclaration()) {
      // The function was already in the module or
      // has already been added in this round of
      // specialization, no need to add it twice
      continue;
    }
    if (optimizer) {
      optimizer->run(*f);
    }
    M.getFunctionList().push_back(f);
  }

  if (modified) {
    errs() << "...progress...\n";
  } else {
    errs() << "...no progress...\n";
  }

  if (policy) {
    delete policy;
  }

  if (optimizer) {
    delete optimizer;
  }

  return modified;
}

void SpecializerPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<CallGraphWrapperPass>();
  AU.setPreservesAll();
}

SpecializerPass::SpecializerPass(bool opt)
  : ModulePass(SpecializerPass::ID)
  , optimize(opt) {
  errs() << "SpecializerPass(" << optimize << ")\n";
}

SpecializerPass::~SpecializerPass() {}

class ParEvalOptPass : public SpecializerPass {
public:
  ParEvalOptPass()
    : SpecializerPass(OptSpecialized.getValue()) {}
};

char SpecializerPass::ID;

} // end namespace previrt

static RegisterPass<previrt::ParEvalOptPass>
X("Ppeval", "Intra-module partial evaluation", false, false);
<commit_msg>Fixes after the code cleanup<commit_after>//
// OCCAM
//
// Copyright (c) 2011-2018, SRI International
//
//  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// * Neither the name of SRI International nor the names of its contributors may
//   be used to endorse or promote products derived from this software without
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

/**
 * Intra-module specialization.
 **/

#include "llvm/Pass.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/IR/CallSite.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
//#include "llvm/Transforms/IPO/PassManagerBuilder.h"

#include "SpecializationTable.h"
#include "Specializer.h"
/* here specialization policies */
#include "AggressiveSpecPolicy.h"
#include "RecursiveGuardSpecPolicy.h"

using namespace llvm;
using namespace previrt;

static cl::opt<bool>
OptSpecialized("Ppeval-opt", cl::Hidden,
	       cl::init(false),
	       cl::desc("Optimize new specialized functions"));

static cl::opt<SpecializationPolicyType>
SpecPolicy("Ppeval-policy",
	   cl::desc("Intra-module specialization policy"),
	   cl::values
	   (clEnumValN (NOSPECIALIZE, "nospecialize",
			"Skip intra-module specialization"),
	    clEnumValN (AGGRESSIVE, "aggressive",
			"Specialize always if some constant argument"),
	    clEnumValN (NONRECURSIVE_WITH_AGGRESSIVE, "nonrec-aggressive",
			"aggressive + non-recursive function")),
	   cl::init(NONRECURSIVE_WITH_AGGRESSIVE));

namespace previrt
{

/**
   Return true if any callsite in f is specialized using policy.
**/
static bool trySpecializeFunction(Function* f, SpecializationTable& table,
				  SpecializationPolicy* policy,
				  std::vector<Function*>& to_add) {

  std::vector<Instruction*> worklist;
  for (BasicBlock& bb: *f) {
    for (Instruction& I: bb) {

      Instruction* ci = dyn_cast<CallInst>(&I);
      if (!ci) ci = dyn_cast<InvokeInst>(&I);
      if (!ci) continue;
      CallSite call(ci);

      Function* callee = call.getCalledFunction();
      if (!callee) {
	continue;
      }

      if (callee->isDeclaration() || callee->isVarArg()) {
        continue;
      }

      if (callee->hasFnAttribute(Attribute::NoInline) ||
      	  callee->hasFnAttribute(Attribute::OptimizeNone)) {
        continue;
      }

      worklist.push_back(ci);
    }
  }

  bool modified = false;
  while (!worklist.empty()) {
    Instruction* ci = worklist.back();
    worklist.pop_back();

    CallSite cs(ci);
    Function* callee = cs.getCalledFunction();
    assert(callee);

    // specScheme[i] = nullptr if the i-th parameter of the callsite
    //                         cannot be specialized.
    //                 c if the i-th parameter of the callsite is a
    //                   constant c
    std::vector<Value*> specScheme;
    bool specialize = policy->specializeOn(cs, specScheme);

    #if 1
    errs() << "Intra-specializing call to '" << callee->getName()
	   << "' in function '" << ci->getParent()->getParent()->getName()
	   << "' on arguments [";
    for (unsigned int i = 0, cnt = 0; i < callee->arg_size(); ++i) {
      if (specScheme[i] != NULL) {
	if (cnt++ != 0)
	  errs() << ",";
          Value* v = cs.getInstruction()->getOperand(i);
          if (GlobalValue* gv = dyn_cast<GlobalValue>(v)) {
            errs() << i << "=(@" << gv->getName() << ")";
          } else {
            errs() << i << "=(" << *cs.getInstruction()->getOperand(i) << ")";
          }
      }
    }
    errs() << "]\n";
    #endif

    if (!specialize) {
      continue;
    }

    // --- build a specialized function if specScheme is more
    //     refined than all existing specialized versions.
    Function* specializedVersion = nullptr;
    std::vector<const SpecializationTable::Specialization*> versions;
    table.getSpecializations(callee, specScheme, versions);
    for (std::vector<const SpecializationTable::Specialization*>::iterator i =
	   versions.begin(), e = versions.end(); i != e; ++i) {
      if (SpecializationTable::Specialization::refines(specScheme, (*i)->args)) {
	specializedVersion = (*i)->handle;
	break;
      }
    }

    if (!specializedVersion) {
      specializedVersion = specializeFunction(callee, specScheme);
      if(!specializedVersion) {
	continue;
      }
      table.addSpecialization(callee, specScheme, specializedVersion);
      to_add.push_back(specializedVersion);
    }

    // -- build the specialized callsite
    const unsigned int specialized_arg_count = specializedVersion->arg_size();
    std::vector<unsigned> argPerm;
    argPerm.reserve(specialized_arg_count);
    for (unsigned from = 0; from < callee->arg_size(); from++) {
      if (!specScheme[from])
	argPerm.push_back(from);
      }
    assert(specialized_arg_count == argPerm.size());

    Instruction* newInst = specializeCallSite(ci, specializedVersion, argPerm);
    llvm::ReplaceInstWithInst(ci, newInst);

    modified = true;
  }

  return modified;
}

/* Intra-module specialization */
class SpecializerPass : public llvm::ModulePass {
private:
  bool optimize;

public:
  static char ID;

  SpecializerPass(bool);
  virtual ~SpecializerPass();
  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const;
  virtual bool runOnModule(llvm::Module &M);
  virtual llvm::StringRef getPassName() const {
    return "Intra-module specializer";
  }
};

bool SpecializerPass::runOnModule(Module &M) {

  // -- Create the specialization policy. Bail out if no policy.
  SpecializationPolicy* policy = nullptr;
  switch (SpecPolicy) {
    case NOSPECIALIZE:
      return false;
    case AGGRESSIVE:
      policy = new AggressiveSpecPolicy();
      break;
    case NONRECURSIVE_WITH_AGGRESSIVE: {
      SpecializationPolicy* subpolicy = new AggressiveSpecPolicy();
      CallGraph& cg = getAnalysis<CallGraphWrapperPass>().getCallGraph();
      policy = new RecursiveGuardSpecPolicy(subpolicy, cg);
      break;
    }
  }

  // -- Specialize functions defined in M
  std::vector<Function*> to_add;
  SpecializationTable table(&M);
  bool modified = false;
  for (auto &f: M) {
    if(f.isDeclaration()) continue;
    modified |= trySpecializeFunction(&f, table, policy, to_add);
  }

  // -- Optimize new function and add it into the module
  llvm::legacy::FunctionPassManager* optimizer = nullptr;
  if (optimize) {
    optimizer = new llvm::legacy::FunctionPassManager(&M);
    //PassManagerBuilder builder;
    //builder.OptLevel = 3;
    //builder.populateFunctionPassManager(*optimizer);
  }

  while (!to_add.empty()) {
    Function* f = to_add.back();
    to_add.pop_back();
    if (f->getParent() == &M  || f->isDeclaration()) {
      // The function was already in the module or
      // has already been added in this round of
      // specialization, no need to add it twice
      continue;
    }
    if (optimizer) {
      optimizer->run(*f);
    }
    M.getFunctionList().push_back(f);
  }

  if (modified) {
    errs() << "...progress...\n";
  } else {
    errs() << "...no progress...\n";
  }

  if (policy) {
    delete policy;
  }

  if (optimizer) {
    delete optimizer;
  }

  return modified;
}

void SpecializerPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<CallGraphWrapperPass>();
  AU.setPreservesAll();
}

SpecializerPass::SpecializerPass(bool opt)
  : ModulePass(SpecializerPass::ID)
  , optimize(opt) {
  errs() << "SpecializerPass(" << optimize << ")\n";
}

SpecializerPass::~SpecializerPass() {}

class ParEvalOptPass : public SpecializerPass {
public:
  ParEvalOptPass()
    : SpecializerPass(OptSpecialized.getValue()) {}
};

char SpecializerPass::ID;

} // end namespace previrt

static RegisterPass<previrt::ParEvalOptPass>
X("Ppeval", "Intra-module partial evaluation", false, false);
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 <deque>
#include <string>

#include <process/defer.hpp>
#include <process/dispatch.hpp>
#include <process/future.hpp>
#include <process/owned.hpp>
#include <process/process.hpp>

#include <stout/lambda.hpp>
#include <stout/none.hpp>
#include <stout/nothing.hpp>
#include <stout/option.hpp>

#include "common/type_utils.hpp"

#include "master/registrar.hpp"
#include "master/registry.hpp"

#include "state/protobuf.hpp"

using mesos::internal::state::protobuf::State;
using mesos::internal::state::protobuf::Variable;

using process::dispatch;
using process::Failure;
using process::Future;
using process::Owned;
using process::Process;
using process::Promise;
using process::spawn;
using process::terminate;
using process::wait; // Necessary on some OS's to disambiguate.

using std::deque;
using std::string;

namespace mesos {
namespace internal {
namespace master {

class RegistrarProcess : public Process<RegistrarProcess>
{
public:
  RegistrarProcess(State* _state)
    : ProcessBase("registrar"),
      updating(false),
      state(_state) {}

  virtual ~RegistrarProcess() {}

  // Registrar implementation.
  Future<Registry> recover(const MasterInfo& info);
  Future<bool> admit(const SlaveInfo& info);
  Future<bool> readmit(const SlaveInfo& info);
  Future<bool> remove(const SlaveInfo& info);

private:
  template <typename T>
  struct Operation : process::Promise<bool>
  {
    Operation() : success(false) {}

    // Attempts to invoke the operation on 't'.
    // Returns Some if the operation mutates 't'.
    // Returns None if the operation does not mutate 't'.
    // Returns Error if the operation cannot be performed on 't'.
    Result<T> operator () (T t)
    {
      const Result<T>& result = perform(t);

      success = !result.isError();

      return result;
    }

    // Sets the promise based on whether the operation was successful.
    bool set() { return Promise<bool>::set(success); }

  protected:
    virtual Result<T> perform(T t) = 0;

  private:
    bool success;
  };

  // The 'Recover' operation adds the latest MasterInfo.
  struct Recover : Operation<Registry>
  {
    Recover(const MasterInfo& _info) : info(_info) {}

  protected:
    virtual Result<Registry> perform(Registry registry)
    {
      registry.mutable_master()->mutable_info()->CopyFrom(info);
      return registry;
    }

    const MasterInfo info;
  };

  // Slave Admission.
  struct Admit : Operation<Registry>
  {
    Admit(const SlaveInfo& _info) : info(_info) {}

  protected:
    virtual Result<Registry> perform(Registry registry)
    {
      // Check and see if this slave already exists.
      foreach (const Registry::Slave& slave, registry.slaves().slaves()) {
        if (slave.info().id() == info.id()) {
          return Error("Slave already admitted");
        }
      }

      Registry::Slave* slave = registry.mutable_slaves()->add_slaves();
      slave->mutable_info()->CopyFrom(info);
      return registry;
    }

    const SlaveInfo info;
  };

  // Slave Readmission.
  struct Readmit : Operation<Registry>
  {
    Readmit(const SlaveInfo& _info) : info(_info) {}

  protected:
    virtual Result<Registry> perform(Registry registry)
    {
      foreach (const Registry::Slave& slave, registry.slaves().slaves()) {
        if (slave.info().id() == info.id()) {
          return None();
        }
      }

      return Error("Slave not yet admitted");
    }

    const SlaveInfo info;
  };

  // Slave Removal.
  struct Remove : Operation<Registry>
  {
    Remove(const SlaveInfo& _info) : info(_info) {}

  protected:
    virtual Result<Registry> perform(Registry registry)
    {
      for (int i = 0; i < registry.slaves().slaves().size(); i++) {
        const Registry::Slave& slave = registry.slaves().slaves(i);
        if (slave.info().id() == info.id()) {
          for (int j = i + 1; j < registry.slaves().slaves().size(); j++) {
            registry.mutable_slaves()->mutable_slaves()->SwapElements(j - 1, j);
          }
          registry.mutable_slaves()->mutable_slaves()->RemoveLast();
          return registry;
        }
      }

      return Error("Slave not yet admitted");
    }

    const SlaveInfo info;
  };

  Option<Variable<Registry> > variable;
  deque<Operation<Registry>*> operations;
  bool updating; // Used to signify fetching (recovering) or storing.

  // Continuations.
  void _recover(
      const MasterInfo& info,
      const Future<Variable<Registry> >& recovery);
  void __recover(const Future<bool>& recover);
  Future<bool> _admit(const SlaveInfo& info);
  Future<bool> _readmit(const SlaveInfo& info);
  Future<bool> _remove(const SlaveInfo& info);

  // Helper for updating state (performing store).
  void update();
  void _update(
      const Future<Option<Variable<Registry> > >& store,
      deque<Operation<Registry>*> operations);

  State* state;

  // Used to compose our operations with recovery.
  Option<Owned<Promise<Registry> > > recovered;
};

Future<Registry> RegistrarProcess::recover(const MasterInfo& info)
{
  LOG(INFO) << "Recovering registrar";

  if (recovered.isNone()) {
    // TODO(benh): Don't wait forever to recover?
    state->fetch<Registry>("registry")
      .onAny(defer(self(), &Self::_recover, info, lambda::_1));
    updating = true;
    recovered = Owned<Promise<Registry> >(new Promise<Registry>());
  }

  return recovered.get()->future();
}

void RegistrarProcess::_recover(
    const MasterInfo& info,
    const Future<Variable<Registry> >& recovery)
{
  updating = false;

  CHECK(!recovery.isPending());

  if (!recovery.isReady()) {
    recovered.get()->fail("Failed to recover registrar: " +
        (recovery.isFailed() ? recovery.failure() : "discarded"));
  } else {
    LOG(INFO) << "Successfully recovered registrar";

    // Save the registry.
    variable = recovery.get();

    // Perform the Recover operation to add the new MasterInfo.
    Operation<Registry>* operation = new Recover(info);
    operations.push_back(operation);
    operation->future()
      .onAny(defer(self(), &Self::__recover, lambda::_1));

    update();
  }
}

void RegistrarProcess::__recover(const Future<bool>& recover)
{
  CHECK(!recover.isPending());

  if (!recover.isReady()) {
    recovered.get()->fail("Failed to recover registrar: "
        "Failed to persist MasterInfo: " +
        (recover.isFailed() ? recover.failure() : "discarded"));
  } else if (!recover.get()) {
    recovered.get()->fail("Failed to recover registrar: "
        "Failed to persist MasterInfo: version mismatch");
  } else {
    // At this point _update() has updated 'variable' to contain
    // the Registry with the latest MasterInfo.
    // Set the promise and un-gate any pending operations.
    CHECK_SOME(variable);
    recovered.get()->set(variable.get().get());
  }
}

Future<bool> RegistrarProcess::admit(const SlaveInfo& info)
{
  if (!info.has_id()) {
    return Failure("SlaveInfo is missing the 'id' field");
  }

  if (recovered.isNone()) {
    return Failure("Attempted to admit slave before recovering");
  }

  return recovered.get()->future()
    .then(defer(self(), &Self::_admit, info));
}

Future<bool> RegistrarProcess::_admit(const SlaveInfo& info)
{
  CHECK_SOME(variable);

  Operation<Registry>* operation = new Admit(info);
  operations.push_back(operation);
  Future<bool> future = operation->future();
  if (!updating) {
    update();
  }
  return future;
}

Future<bool> RegistrarProcess::readmit(const SlaveInfo& info)
{
  if (!info.has_id()) {
    return Failure("SlaveInfo is missing the 'id' field");
  }

  if (recovered.isNone()) {
    return Failure("Attempted to readmit slave before recovering");
  }

  return recovered.get()->future()
    .then(defer(self(), &Self::_readmit, info));
}

Future<bool> RegistrarProcess::_readmit(
    const SlaveInfo& info)
{
  CHECK_SOME(variable);

  Operation<Registry>* operation = new Readmit(info);
  operations.push_back(operation);
  Future<bool> future = operation->future();
  if (!updating) {
    update();
  }
  return future;
}

Future<bool> RegistrarProcess::remove(const SlaveInfo& info)
{
  if (!info.has_id()) {
    return Failure("SlaveInfo is missing the 'id' field");
  }

  if (recovered.isNone()) {
    return Failure("Attempted to remove slave before recovering");
  }

  return recovered.get()->future()
    .then(defer(self(), &Self::_remove, info));
}

Future<bool> RegistrarProcess::_remove(
    const SlaveInfo& info)
{
  CHECK_SOME(variable);

  Operation<Registry>* operation = new Remove(info);
  operations.push_back(operation);
  Future<bool> future = operation->future();
  if (!updating) {
    update();
  }
  return future;
}

void RegistrarProcess::update()
{
  if (operations.empty()) {
    return; // No-op.
  }

  CHECK(!updating);

  updating = true;

  LOG(INFO) << "Attempting to update the 'registry'";

  CHECK_SOME(variable);

  Variable<Registry> variable_ = variable.get();

  foreach (Operation<Registry>* operation, operations) {
    const Result<Registry>& registry = (*operation)(variable_.get());
    if (registry.isSome()) {
      variable_ = variable_.mutate(registry.get());
    }
  }

  // TODO(benh): Add a timeout so we don't wait forever.

  // Perform the store!
  state->store(variable_)
    .onAny(defer(self(), &Self::_update, lambda::_1, operations));

  // Clear the operations, _update will transition the Promises!
  operations.clear();
}

void RegistrarProcess::_update(
    const Future<Option<Variable<Registry> > >& store,
    deque<Operation<Registry>*> operations)
{
  updating = false;

  // Set the variable if the storage operation succeeded.
  if (!store.isReady()) {
    LOG(ERROR) << "Failed to update 'registry': "
               << (store.isFailed() ? store.failure() : "discarded");
  } else if (store.get().isNone()) {
    LOG(WARNING) << "Failed to update 'registry': version mismatch";
  } else {
    LOG(INFO) << "Successfully updated 'registry'";
    variable = store.get().get();
  }

  // Remove the operations.
  while (!operations.empty()) {
    Operation<Registry>* operation = operations.front();
    operations.pop_front();

    if (!store.isReady()) {
      operation->fail("Failed to update 'registry': " +
          (store.isFailed() ? store.failure() : "discarded"));
    } else {
      if (store.get().isNone()) {
        operation->fail("Failed to update 'registry': version mismatch");
      } else {
        operation->set();
      }
    }

    delete operation;
  }

  operations.clear();

  if (!this->operations.empty()) {
    update();
  }
}

Registrar::Registrar(State* state)
{
  process = new RegistrarProcess(state);
  spawn(process);
}

Registrar::~Registrar()
{
  terminate(process);
  wait(process);
}

Future<Registry> Registrar::recover(const MasterInfo& info)
{
  return dispatch(process, &RegistrarProcess::recover, info);
}

Future<bool> Registrar::admit(const SlaveInfo& info)
{
  return dispatch(process, &RegistrarProcess::admit, info);
}

Future<bool> Registrar::readmit(const SlaveInfo& info)
{
  return dispatch(process, &RegistrarProcess::readmit, info);
}

Future<bool> Registrar::remove(const SlaveInfo& info)
{
  return dispatch(process, &RegistrarProcess::remove, info);
}

} // namespace master {
} // namespace internal {
} // namespace mesos {
<commit_msg>Performance optimizations to the Registrar.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 <deque>
#include <string>

#include <process/defer.hpp>
#include <process/dispatch.hpp>
#include <process/future.hpp>
#include <process/owned.hpp>
#include <process/process.hpp>

#include <stout/lambda.hpp>
#include <stout/none.hpp>
#include <stout/nothing.hpp>
#include <stout/option.hpp>

#include "common/type_utils.hpp"

#include "master/registrar.hpp"
#include "master/registry.hpp"

#include "state/protobuf.hpp"

using mesos::internal::state::protobuf::State;
using mesos::internal::state::protobuf::Variable;

using process::dispatch;
using process::Failure;
using process::Future;
using process::Owned;
using process::Process;
using process::Promise;
using process::spawn;
using process::terminate;
using process::wait; // Necessary on some OS's to disambiguate.

using std::deque;
using std::string;

namespace mesos {
namespace internal {
namespace master {

class RegistrarProcess : public Process<RegistrarProcess>
{
public:
  RegistrarProcess(State* _state)
    : ProcessBase("registrar"),
      updating(false),
      state(_state) {}

  virtual ~RegistrarProcess() {}

  // Registrar implementation.
  Future<Registry> recover(const MasterInfo& info);
  Future<bool> admit(const SlaveInfo& info);
  Future<bool> readmit(const SlaveInfo& info);
  Future<bool> remove(const SlaveInfo& info);

private:
  template <typename T>
  struct Operation : process::Promise<bool>
  {
    Operation() : success(false) {}

    // Attempts to invoke the operation on 't'.
    // Returns whether the operation mutates 't', or an error if the
    // operation cannot be applied successfully.
    Try<bool> operator () (T* t)
    {
      const Try<bool>& result = perform(t);

      success = !result.isError();

      return result;
    }

    // Sets the promise based on whether the operation was successful.
    bool set() { return Promise<bool>::set(success); }

  protected:
    virtual Try<bool> perform(T* t) = 0;

  private:
    bool success;
  };

  // The 'Recover' operation adds the latest MasterInfo.
  struct Recover : Operation<Registry>
  {
    Recover(const MasterInfo& _info) : info(_info) {}

  protected:
    virtual Try<bool> perform(Registry* registry)
    {
      registry->mutable_master()->mutable_info()->CopyFrom(info);
      return true;
    }

    const MasterInfo info;
  };

  // Slave Admission.
  struct Admit : Operation<Registry>
  {
    Admit(const SlaveInfo& _info) : info(_info) {}

  protected:
    virtual Try<bool> perform(Registry* registry)
    {
      // Check and see if this slave already exists.
      foreach (const Registry::Slave& slave, registry->slaves().slaves()) {
        if (slave.info().id() == info.id()) {
          return Error("Slave already admitted");
        }
      }

      Registry::Slave* slave = registry->mutable_slaves()->add_slaves();
      slave->mutable_info()->CopyFrom(info);
      return true;
    }

    const SlaveInfo info;
  };

  // Slave Readmission.
  struct Readmit : Operation<Registry>
  {
    Readmit(const SlaveInfo& _info) : info(_info) {}

  protected:
    virtual Try<bool> perform(Registry* registry)
    {
      foreach (const Registry::Slave& slave, registry->slaves().slaves()) {
        if (slave.info().id() == info.id()) {
          return false;
        }
      }

      return Error("Slave not yet admitted");
    }

    const SlaveInfo info;
  };

  // Slave Removal.
  struct Remove : Operation<Registry>
  {
    Remove(const SlaveInfo& _info) : info(_info) {}

  protected:
    virtual Try<bool> perform(Registry* registry)
    {
      for (int i = 0; i < registry->slaves().slaves().size(); i++) {
        const Registry::Slave& slave = registry->slaves().slaves(i);
        if (slave.info().id() == info.id()) {
          for (int j = i + 1; j < registry->slaves().slaves().size(); j++) {
            registry->
                mutable_slaves()->mutable_slaves()->SwapElements(j - 1, j);
          }
          registry->mutable_slaves()->mutable_slaves()->RemoveLast();
          return true;
        }
      }

      return Error("Slave not yet admitted");
    }

    const SlaveInfo info;
  };

  Option<Variable<Registry> > variable;
  deque<Operation<Registry>*> operations;
  bool updating; // Used to signify fetching (recovering) or storing.

  // Continuations.
  void _recover(
      const MasterInfo& info,
      const Future<Variable<Registry> >& recovery);
  void __recover(const Future<bool>& recover);
  Future<bool> _admit(const SlaveInfo& info);
  Future<bool> _readmit(const SlaveInfo& info);
  Future<bool> _remove(const SlaveInfo& info);

  // Helper for updating state (performing store).
  void update();
  void _update(
      const Future<Option<Variable<Registry> > >& store,
      deque<Operation<Registry>*> operations);

  State* state;

  // Used to compose our operations with recovery.
  Option<Owned<Promise<Registry> > > recovered;
};

Future<Registry> RegistrarProcess::recover(const MasterInfo& info)
{
  LOG(INFO) << "Recovering registrar";

  if (recovered.isNone()) {
    // TODO(benh): Don't wait forever to recover?
    state->fetch<Registry>("registry")
      .onAny(defer(self(), &Self::_recover, info, lambda::_1));
    updating = true;
    recovered = Owned<Promise<Registry> >(new Promise<Registry>());
  }

  return recovered.get()->future();
}

void RegistrarProcess::_recover(
    const MasterInfo& info,
    const Future<Variable<Registry> >& recovery)
{
  updating = false;

  CHECK(!recovery.isPending());

  if (!recovery.isReady()) {
    recovered.get()->fail("Failed to recover registrar: " +
        (recovery.isFailed() ? recovery.failure() : "discarded"));
  } else {
    LOG(INFO) << "Successfully recovered registrar";

    // Save the registry.
    variable = recovery.get();

    // Perform the Recover operation to add the new MasterInfo.
    Operation<Registry>* operation = new Recover(info);
    operations.push_back(operation);
    operation->future()
      .onAny(defer(self(), &Self::__recover, lambda::_1));

    update();
  }
}

void RegistrarProcess::__recover(const Future<bool>& recover)
{
  CHECK(!recover.isPending());

  if (!recover.isReady()) {
    recovered.get()->fail("Failed to recover registrar: "
        "Failed to persist MasterInfo: " +
        (recover.isFailed() ? recover.failure() : "discarded"));
  } else if (!recover.get()) {
    recovered.get()->fail("Failed to recover registrar: "
        "Failed to persist MasterInfo: version mismatch");
  } else {
    // At this point _update() has updated 'variable' to contain
    // the Registry with the latest MasterInfo.
    // Set the promise and un-gate any pending operations.
    CHECK_SOME(variable);
    recovered.get()->set(variable.get().get());
  }
}

Future<bool> RegistrarProcess::admit(const SlaveInfo& info)
{
  if (!info.has_id()) {
    return Failure("SlaveInfo is missing the 'id' field");
  }

  if (recovered.isNone()) {
    return Failure("Attempted to admit slave before recovering");
  }

  return recovered.get()->future()
    .then(defer(self(), &Self::_admit, info));
}

Future<bool> RegistrarProcess::_admit(const SlaveInfo& info)
{
  CHECK_SOME(variable);

  Operation<Registry>* operation = new Admit(info);
  operations.push_back(operation);
  Future<bool> future = operation->future();
  if (!updating) {
    update();
  }
  return future;
}

Future<bool> RegistrarProcess::readmit(const SlaveInfo& info)
{
  if (!info.has_id()) {
    return Failure("SlaveInfo is missing the 'id' field");
  }

  if (recovered.isNone()) {
    return Failure("Attempted to readmit slave before recovering");
  }

  return recovered.get()->future()
    .then(defer(self(), &Self::_readmit, info));
}

Future<bool> RegistrarProcess::_readmit(
    const SlaveInfo& info)
{
  CHECK_SOME(variable);

  Operation<Registry>* operation = new Readmit(info);
  operations.push_back(operation);
  Future<bool> future = operation->future();
  if (!updating) {
    update();
  }
  return future;
}

Future<bool> RegistrarProcess::remove(const SlaveInfo& info)
{
  if (!info.has_id()) {
    return Failure("SlaveInfo is missing the 'id' field");
  }

  if (recovered.isNone()) {
    return Failure("Attempted to remove slave before recovering");
  }

  return recovered.get()->future()
    .then(defer(self(), &Self::_remove, info));
}

Future<bool> RegistrarProcess::_remove(
    const SlaveInfo& info)
{
  CHECK_SOME(variable);

  Operation<Registry>* operation = new Remove(info);
  operations.push_back(operation);
  Future<bool> future = operation->future();
  if (!updating) {
    update();
  }
  return future;
}

void RegistrarProcess::update()
{
  if (operations.empty()) {
    return; // No-op.
  }

  CHECK(!updating);

  updating = true;

  LOG(INFO) << "Attempting to update the 'registry'";

  CHECK_SOME(variable);

  Registry registry = variable.get().get();

  foreach (Operation<Registry>* operation, operations) {
    // No need to process the result of the operation.
    (*operation)(&registry);
  }

  // TODO(benh): Add a timeout so we don't wait forever.

  // Perform the store!
  state->store(variable.get().mutate(registry))
    .onAny(defer(self(), &Self::_update, lambda::_1, operations));

  // Clear the operations, _update will transition the Promises!
  operations.clear();
}

void RegistrarProcess::_update(
    const Future<Option<Variable<Registry> > >& store,
    deque<Operation<Registry>*> operations)
{
  updating = false;

  // Set the variable if the storage operation succeeded.
  if (!store.isReady()) {
    LOG(ERROR) << "Failed to update 'registry': "
               << (store.isFailed() ? store.failure() : "discarded");
  } else if (store.get().isNone()) {
    LOG(WARNING) << "Failed to update 'registry': version mismatch";
  } else {
    LOG(INFO) << "Successfully updated 'registry'";
    variable = store.get().get();
  }

  // Remove the operations.
  while (!operations.empty()) {
    Operation<Registry>* operation = operations.front();
    operations.pop_front();

    if (!store.isReady()) {
      operation->fail("Failed to update 'registry': " +
          (store.isFailed() ? store.failure() : "discarded"));
    } else {
      if (store.get().isNone()) {
        operation->fail("Failed to update 'registry': version mismatch");
      } else {
        operation->set();
      }
    }

    delete operation;
  }

  operations.clear();

  if (!this->operations.empty()) {
    update();
  }
}

Registrar::Registrar(State* state)
{
  process = new RegistrarProcess(state);
  spawn(process);
}

Registrar::~Registrar()
{
  terminate(process);
  wait(process);
}

Future<Registry> Registrar::recover(const MasterInfo& info)
{
  return dispatch(process, &RegistrarProcess::recover, info);
}

Future<bool> Registrar::admit(const SlaveInfo& info)
{
  return dispatch(process, &RegistrarProcess::admit, info);
}

Future<bool> Registrar::readmit(const SlaveInfo& info)
{
  return dispatch(process, &RegistrarProcess::readmit, info);
}

Future<bool> Registrar::remove(const SlaveInfo& info)
{
  return dispatch(process, &RegistrarProcess::remove, info);
}

} // namespace master {
} // namespace internal {
} // namespace mesos {
<|endoftext|>


<commit_before>#pragma once
#include "interval_index.hpp"
#include "../coding/byte_stream.hpp"
#include "../coding/endianness.hpp"
#include "../coding/varint.hpp"
#include "../coding/write_to_sink.hpp"
#include "../base/assert.hpp"
#include "../base/base.hpp"
#include "../base/bits.hpp"
#include "../base/logging.hpp"
#include "../std/vector.hpp"
#include "../std/memcpy.hpp"

// +------------------------------+
// |            Header            |
// +------------------------------+
// |        Leaves  offset        |
// +------------------------------+
// |        Level 1 offset        |
// +------------------------------+
// |             ...              |
// +------------------------------+
// |        Level N offset        |
// +------------------------------+
// |        Leaves  data          |
// +------------------------------+
// |        Level 1 data          |
// +------------------------------+
// |             ...              |
// +------------------------------+
// |        Level N data          |
// +------------------------------+

class IntervalIndexBuilder
{
public:
  IntervalIndexBuilder(uint32_t keyBits, uint32_t leafBytes, uint32_t bitsPerLevel = 8)
    : m_BitsPerLevel(bitsPerLevel), m_LeafBytes(leafBytes)
  {
    CHECK_GREATER(leafBytes, 0, ());
    CHECK_LESS(keyBits, 63, ());
    int const nodeKeyBits = keyBits - (m_LeafBytes << 3);
    CHECK_GREATER(nodeKeyBits, 0, (keyBits, leafBytes));
    m_Levels = (nodeKeyBits + m_BitsPerLevel - 1) / m_BitsPerLevel;
    m_LastBitsMask = (1 << m_BitsPerLevel) - 1;
  }

  uint32_t GetLevelCount() const { return m_Levels; }

  template <class WriterT, typename CellIdValueIterT>
  void BuildIndex(WriterT & writer, CellIdValueIterT const & beg, CellIdValueIterT const & end)
  {
    CHECK(CheckIntervalIndexInputSequence(beg, end), ());

    if (beg == end)
    {
      IntervalIndexBase::Header header;
      header.m_Version = IntervalIndexBase::kVersion;
      header.m_BitsPerLevel = 0;
      header.m_Levels = 0;
      header.m_LeafBytes = 0;
      writer.Write(&header, sizeof(header));
      return;
    }

    uint64_t const initialPos = writer.Pos();
    WriteZeroesToSink(writer, sizeof(IntervalIndexBase::Header));
    WriteZeroesToSink(writer, 4 * (m_Levels + 2));
    uint64_t const afterHeaderPos = writer.Pos();

    vector<uint32_t> levelOffset;
    {
      vector<uint32_t> offsets;
      levelOffset.push_back(static_cast<uint32_t>(writer.Pos()));
      BuildLeaves(writer, beg, end, offsets);
      levelOffset.push_back(static_cast<uint32_t>(writer.Pos()));
      for (int i = 1; i <= static_cast<int>(m_Levels); ++i)
      {
        vector<uint32_t> nextOffsets;
        BuildLevel(writer, beg, end, i, &offsets[0], &offsets[0] + offsets.size(), nextOffsets);
        nextOffsets.swap(offsets);
        levelOffset.push_back(static_cast<uint32_t>(writer.Pos()));
      }
    }

    uint64_t const lastPos = writer.Pos();
    writer.Seek(initialPos);

    // Write header.
    {
      IntervalIndexBase::Header header;
      header.m_Version = IntervalIndexBase::kVersion;
      header.m_BitsPerLevel = m_BitsPerLevel;
      header.m_Levels = m_Levels;
      header.m_LeafBytes = m_LeafBytes;
      writer.Write(&header, sizeof(header));
    }

    // Write level offsets.
    for (size_t i = 0; i < levelOffset.size(); ++i)
      WriteToSink(writer, levelOffset[i]);

    uint64_t const pos = writer.Pos();
    CHECK_EQUAL(pos, afterHeaderPos, ());
    writer.Seek(lastPos);
  }

  template <typename CellIdValueIterT>
  bool CheckIntervalIndexInputSequence(CellIdValueIterT const & beg, CellIdValueIterT const & end)
  {
    // Check that [beg, end) is sorted and log most populous cell.
    if (beg != end)
    {
      uint32_t count = 0;
      uint32_t maxCount = 0;
      typename CellIdValueIterT::value_type mostPopulousCell = *beg;
      CellIdValueIterT it = beg;
      uint64_t prev = it->GetCell();
      for (++it; it != end; ++it)
      {
        CHECK_GREATER(it->GetCell(), 0, ());
        CHECK_LESS_OR_EQUAL(prev, it->GetCell(), ());
        count = (prev == it->GetCell() ? count + 1 : 0);
        if (count > maxCount)
        {
          maxCount = count;
          mostPopulousCell = *it;
        }
        prev = it->GetCell();
      }
      if (maxCount > 0)
      {
        LOG(LINFO, ("Most populous cell:", maxCount,
                    mostPopulousCell.GetCell(), mostPopulousCell.GetFeature()));
      }
    }

    uint32_t const keyBits = 8 * m_LeafBytes + m_Levels * m_BitsPerLevel;
    for (CellIdValueIterT it = beg; it != end; ++it)
    {
      CHECK_LESS(it->GetCell(), 1ULL << keyBits, ());
      CHECK_EQUAL(it->GetFeature(), static_cast<uint32_t>(it->GetFeature()), ());
    }

    return true;
  }

  template <class SinkT>
  uint32_t WriteNode(SinkT & sink, uint32_t offset, uint32_t * childSizes)
  {
    vector<uint8_t> bitmapSerial, listSerial;
    bitmapSerial.reserve(1024);
    listSerial.reserve(1024);
    PushBackByteSink<vector<uint8_t> > bitmapSink(bitmapSerial), listSink(listSerial);
    WriteBitmapNode(bitmapSink, offset, childSizes);
    WriteListNode(listSink, offset, childSizes);
    if (bitmapSerial.size() <= listSerial.size())
    {
      sink.Write(&bitmapSerial[0], bitmapSerial.size());
      return bitmapSerial.size();
    }
    else
    {
      sink.Write(&listSerial[0], listSerial.size());
      return listSerial.size();
    }
  }

  template <class WriterT, typename CellIdValueIterT>
  void BuildLevel(WriterT & writer, CellIdValueIterT const & beg, CellIdValueIterT const & end,
                  int level, uint32_t const * childSizesBeg, uint32_t const * childSizesEnd,
                  vector<uint32_t> & sizes)
  {
    UNUSED_VALUE(childSizesEnd);
    ASSERT_GREATER(level, 0, ());
    uint32_t const skipBits = m_LeafBytes * 8 + (level - 1) * m_BitsPerLevel;
    vector<uint32_t> expandedSizes(1 << m_BitsPerLevel);
    uint64_t prevKey = -1;
    uint32_t childOffset = 0;
    uint32_t nextChildOffset = 0;
    for (CellIdValueIterT it = beg; it != end; ++it)
    {
      uint64_t const key = it->GetCell() >> skipBits;
      if (key == prevKey)
        continue;

      if (it != beg && (key >> m_BitsPerLevel) != (prevKey >> m_BitsPerLevel))
      {
        sizes.push_back(WriteNode(writer, childOffset, &expandedSizes[0]));
        childOffset = nextChildOffset;
        expandedSizes.assign(expandedSizes.size(), 0);
      }

      nextChildOffset += *childSizesBeg;
      expandedSizes[key & m_LastBitsMask] +=  *childSizesBeg;
      ++childSizesBeg;
      prevKey = key;
    }
    sizes.push_back(WriteNode(writer, childOffset, &expandedSizes[0]));
    ASSERT_EQUAL(childSizesBeg, childSizesEnd, ());
  }

  template <class WriterT, typename CellIdValueIterT>
  void BuildLeaves(WriterT & writer, CellIdValueIterT const & beg, CellIdValueIterT const & end,
                   vector<uint32_t> & sizes)
  {
    uint32_t const skipBits = 8 * m_LeafBytes;
    uint64_t prevKey = 0;
    uint64_t prevValue = 0;
    uint64_t prevPos = writer.Pos();
    for (CellIdValueIterT it = beg; it != end; ++it)
    {
      uint64_t const key = it->GetCell();
      uint64_t const value = it->GetFeature();
      if (it != beg && (key >> skipBits) != (prevKey >> skipBits))
      {
        sizes.push_back(static_cast<uint32_t>(writer.Pos() - prevPos));
        prevValue = 0;
        prevPos = writer.Pos();
      }
      uint64_t const keySerial = SwapIfBigEndian(key);
      writer.Write(&keySerial, m_LeafBytes);
      WriteVarInt(writer, static_cast<int64_t>(value) - static_cast<int64_t>(prevValue));
      prevKey = key;
      prevValue = value;
    }
    sizes.push_back(static_cast<uint32_t>(writer.Pos() - prevPos));
  }

  template <class SinkT>
  void WriteBitmapNode(SinkT & sink, uint32_t offset, uint32_t * childSizes)
  {
    ASSERT_GREATER_OR_EQUAL(m_BitsPerLevel, 3, ());
    WriteVarUint(sink, (offset << 1) + 1);
    buffer_vector<uint8_t, 32> bitMask(1 << (m_BitsPerLevel - 3));
    for (uint32_t i = 0; i < static_cast<uint32_t>(1 << m_BitsPerLevel); ++i)
      if (childSizes[i])
        bits::SetBitTo1(&bitMask[0], i);
    sink.Write(&bitMask[0], bitMask.size());
    for (uint32_t i = 0; i < static_cast<uint32_t>(1 << m_BitsPerLevel); ++i)
      if (childSizes[i])
        WriteVarUint(sink, childSizes[i]);
  }

  template <class SinkT>
  void WriteListNode(SinkT & sink, uint32_t offset, uint32_t * childSizes)
  {
    ASSERT_LESS_OR_EQUAL(m_BitsPerLevel, 8, ());
    WriteVarUint(sink, (offset << 1));
    for (uint32_t i = 0; i < static_cast<uint32_t>(1 << m_BitsPerLevel); ++i)
    {
      if (childSizes[i])
      {
        WriteToSink(sink, static_cast<uint8_t>(i));
        WriteVarUint(sink, childSizes[i]);
      }
    }
  }

private:
  uint32_t m_Levels, m_BitsPerLevel, m_LeafBytes, m_LastBitsMask;
};

template <class WriterT, typename CellIdValueIterT>
void BuildIntervalIndex(CellIdValueIterT const & beg, CellIdValueIterT const & end,
                        WriterT & writer, uint32_t keyBits)
{
  IntervalIndexBuilder(keyBits, 1).BuildIndex(writer, beg, end);
}
<commit_msg>Warning fix<commit_after>#pragma once
#include "interval_index.hpp"
#include "../coding/byte_stream.hpp"
#include "../coding/endianness.hpp"
#include "../coding/varint.hpp"
#include "../coding/write_to_sink.hpp"
#include "../base/assert.hpp"
#include "../base/base.hpp"
#include "../base/bits.hpp"
#include "../base/logging.hpp"
#include "../std/vector.hpp"
#include "../std/memcpy.hpp"

// +------------------------------+
// |            Header            |
// +------------------------------+
// |        Leaves  offset        |
// +------------------------------+
// |        Level 1 offset        |
// +------------------------------+
// |             ...              |
// +------------------------------+
// |        Level N offset        |
// +------------------------------+
// |        Leaves  data          |
// +------------------------------+
// |        Level 1 data          |
// +------------------------------+
// |             ...              |
// +------------------------------+
// |        Level N data          |
// +------------------------------+

class IntervalIndexBuilder
{
public:
  IntervalIndexBuilder(uint32_t keyBits, uint32_t leafBytes, uint32_t bitsPerLevel = 8)
    : m_BitsPerLevel(bitsPerLevel), m_LeafBytes(leafBytes)
  {
    CHECK_GREATER(leafBytes, 0, ());
    CHECK_LESS(keyBits, 63, ());
    int const nodeKeyBits = keyBits - (m_LeafBytes << 3);
    CHECK_GREATER(nodeKeyBits, 0, (keyBits, leafBytes));
    m_Levels = (nodeKeyBits + m_BitsPerLevel - 1) / m_BitsPerLevel;
    m_LastBitsMask = (1 << m_BitsPerLevel) - 1;
  }

  uint32_t GetLevelCount() const { return m_Levels; }

  template <class WriterT, typename CellIdValueIterT>
  void BuildIndex(WriterT & writer, CellIdValueIterT const & beg, CellIdValueIterT const & end)
  {
    CHECK(CheckIntervalIndexInputSequence(beg, end), ());

    if (beg == end)
    {
      IntervalIndexBase::Header header;
      header.m_Version = IntervalIndexBase::kVersion;
      header.m_BitsPerLevel = 0;
      header.m_Levels = 0;
      header.m_LeafBytes = 0;
      writer.Write(&header, sizeof(header));
      return;
    }

    uint64_t const initialPos = writer.Pos();
    WriteZeroesToSink(writer, sizeof(IntervalIndexBase::Header));
    WriteZeroesToSink(writer, 4 * (m_Levels + 2));
    uint64_t const afterHeaderPos = writer.Pos();

    vector<uint32_t> levelOffset;
    {
      vector<uint32_t> offsets;
      levelOffset.push_back(static_cast<uint32_t>(writer.Pos()));
      BuildLeaves(writer, beg, end, offsets);
      levelOffset.push_back(static_cast<uint32_t>(writer.Pos()));
      for (int i = 1; i <= static_cast<int>(m_Levels); ++i)
      {
        vector<uint32_t> nextOffsets;
        BuildLevel(writer, beg, end, i, &offsets[0], &offsets[0] + offsets.size(), nextOffsets);
        nextOffsets.swap(offsets);
        levelOffset.push_back(static_cast<uint32_t>(writer.Pos()));
      }
    }

    uint64_t const lastPos = writer.Pos();
    writer.Seek(initialPos);

    // Write header.
    {
      IntervalIndexBase::Header header;
      header.m_Version = IntervalIndexBase::kVersion;
      header.m_BitsPerLevel = m_BitsPerLevel;
      header.m_Levels = m_Levels;
      header.m_LeafBytes = m_LeafBytes;
      writer.Write(&header, sizeof(header));
    }

    // Write level offsets.
    for (size_t i = 0; i < levelOffset.size(); ++i)
      WriteToSink(writer, levelOffset[i]);

    uint64_t const pos = writer.Pos();
    CHECK_EQUAL(pos, afterHeaderPos, ());
    writer.Seek(lastPos);
  }

  template <typename CellIdValueIterT>
  bool CheckIntervalIndexInputSequence(CellIdValueIterT const & beg, CellIdValueIterT const & end)
  {
    // Check that [beg, end) is sorted and log most populous cell.
    if (beg != end)
    {
      uint32_t count = 0;
      uint32_t maxCount = 0;
      typename CellIdValueIterT::value_type mostPopulousCell = *beg;
      CellIdValueIterT it = beg;
      uint64_t prev = it->GetCell();
      for (++it; it != end; ++it)
      {
        CHECK_GREATER(it->GetCell(), 0, ());
        CHECK_LESS_OR_EQUAL(prev, it->GetCell(), ());
        count = (prev == it->GetCell() ? count + 1 : 0);
        if (count > maxCount)
        {
          maxCount = count;
          mostPopulousCell = *it;
        }
        prev = it->GetCell();
      }
      if (maxCount > 0)
      {
        LOG(LINFO, ("Most populous cell:", maxCount,
                    mostPopulousCell.GetCell(), mostPopulousCell.GetFeature()));
      }
    }

    uint32_t const keyBits = 8 * m_LeafBytes + m_Levels * m_BitsPerLevel;
    for (CellIdValueIterT it = beg; it != end; ++it)
    {
      CHECK_LESS(it->GetCell(), 1ULL << keyBits, ());
      CHECK_EQUAL(it->GetFeature(), static_cast<uint32_t>(it->GetFeature()), ());
    }

    return true;
  }

  template <class SinkT>
  uint32_t WriteNode(SinkT & sink, uint32_t offset, uint32_t * childSizes)
  {
    vector<uint8_t> bitmapSerial, listSerial;
    bitmapSerial.reserve(1024);
    listSerial.reserve(1024);
    PushBackByteSink<vector<uint8_t> > bitmapSink(bitmapSerial), listSink(listSerial);
    WriteBitmapNode(bitmapSink, offset, childSizes);
    WriteListNode(listSink, offset, childSizes);
    if (bitmapSerial.size() <= listSerial.size())
    {
      sink.Write(&bitmapSerial[0], bitmapSerial.size());
      return bitmapSerial.size();
    }
    else
    {
      sink.Write(&listSerial[0], listSerial.size());
      return listSerial.size();
    }
  }

  template <class WriterT, typename CellIdValueIterT>
  void BuildLevel(WriterT & writer, CellIdValueIterT const & beg, CellIdValueIterT const & end,
                  int level, uint32_t const * childSizesBeg, uint32_t const * childSizesEnd,
                  vector<uint32_t> & sizes)
  {
    UNUSED_VALUE(childSizesEnd);
    ASSERT_GREATER(level, 0, ());
    uint32_t const skipBits = m_LeafBytes * 8 + (level - 1) * m_BitsPerLevel;
    vector<uint32_t> expandedSizes(1 << m_BitsPerLevel);
    uint64_t prevKey = static_cast<uint64_t>(-1);
    uint32_t childOffset = 0;
    uint32_t nextChildOffset = 0;
    for (CellIdValueIterT it = beg; it != end; ++it)
    {
      uint64_t const key = it->GetCell() >> skipBits;
      if (key == prevKey)
        continue;

      if (it != beg && (key >> m_BitsPerLevel) != (prevKey >> m_BitsPerLevel))
      {
        sizes.push_back(WriteNode(writer, childOffset, &expandedSizes[0]));
        childOffset = nextChildOffset;
        expandedSizes.assign(expandedSizes.size(), 0);
      }

      nextChildOffset += *childSizesBeg;
      expandedSizes[key & m_LastBitsMask] +=  *childSizesBeg;
      ++childSizesBeg;
      prevKey = key;
    }
    sizes.push_back(WriteNode(writer, childOffset, &expandedSizes[0]));
    ASSERT_EQUAL(childSizesBeg, childSizesEnd, ());
  }

  template <class WriterT, typename CellIdValueIterT>
  void BuildLeaves(WriterT & writer, CellIdValueIterT const & beg, CellIdValueIterT const & end,
                   vector<uint32_t> & sizes)
  {
    uint32_t const skipBits = 8 * m_LeafBytes;
    uint64_t prevKey = 0;
    uint64_t prevValue = 0;
    uint64_t prevPos = writer.Pos();
    for (CellIdValueIterT it = beg; it != end; ++it)
    {
      uint64_t const key = it->GetCell();
      uint64_t const value = it->GetFeature();
      if (it != beg && (key >> skipBits) != (prevKey >> skipBits))
      {
        sizes.push_back(static_cast<uint32_t>(writer.Pos() - prevPos));
        prevValue = 0;
        prevPos = writer.Pos();
      }
      uint64_t const keySerial = SwapIfBigEndian(key);
      writer.Write(&keySerial, m_LeafBytes);
      WriteVarInt(writer, static_cast<int64_t>(value) - static_cast<int64_t>(prevValue));
      prevKey = key;
      prevValue = value;
    }
    sizes.push_back(static_cast<uint32_t>(writer.Pos() - prevPos));
  }

  template <class SinkT>
  void WriteBitmapNode(SinkT & sink, uint32_t offset, uint32_t * childSizes)
  {
    ASSERT_GREATER_OR_EQUAL(m_BitsPerLevel, 3, ());
    WriteVarUint(sink, (offset << 1) + 1);
    buffer_vector<uint8_t, 32> bitMask(1 << (m_BitsPerLevel - 3));
    for (uint32_t i = 0; i < static_cast<uint32_t>(1 << m_BitsPerLevel); ++i)
      if (childSizes[i])
        bits::SetBitTo1(&bitMask[0], i);
    sink.Write(&bitMask[0], bitMask.size());
    for (uint32_t i = 0; i < static_cast<uint32_t>(1 << m_BitsPerLevel); ++i)
      if (childSizes[i])
        WriteVarUint(sink, childSizes[i]);
  }

  template <class SinkT>
  void WriteListNode(SinkT & sink, uint32_t offset, uint32_t * childSizes)
  {
    ASSERT_LESS_OR_EQUAL(m_BitsPerLevel, 8, ());
    WriteVarUint(sink, (offset << 1));
    for (uint32_t i = 0; i < static_cast<uint32_t>(1 << m_BitsPerLevel); ++i)
    {
      if (childSizes[i])
      {
        WriteToSink(sink, static_cast<uint8_t>(i));
        WriteVarUint(sink, childSizes[i]);
      }
    }
  }

private:
  uint32_t m_Levels, m_BitsPerLevel, m_LeafBytes, m_LastBitsMask;
};

template <class WriterT, typename CellIdValueIterT>
void BuildIntervalIndex(CellIdValueIterT const & beg, CellIdValueIterT const & end,
                        WriterT & writer, uint32_t keyBits)
{
  IntervalIndexBuilder(keyBits, 1).BuildIndex(writer, beg, end);
}
<|endoftext|>


<commit_before>/*******************************
Copyright (c) 2016-2022 Gr�goire Angerand

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

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

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

#include "EntityWorld.h"

#include <y/utils/log.h>
#include <y/utils/format.h>

#include <yave/assets/AssetLoadingContext.h>

namespace yave {
namespace ecs {

EntityWorld::EntityWorld() {
}

EntityWorld::~EntityWorld() {
    for(auto& system : _systems) {
        system->destroy(*this);
    }
    _containers.clear();
}

EntityWorld::EntityWorld(EntityWorld&& other) {
    swap(other);
}

EntityWorld& EntityWorld::operator=(EntityWorld&& other) {
    swap(other);
    return *this;
}

void EntityWorld::swap(EntityWorld& other) {
    if(this != &other) {
        std::swap(_containers, other._containers);
        std::swap(_tags, other._tags);
        std::swap(_entities, other._entities);
        std::swap(_required_components, other._required_components);
        std::swap(_systems, other._systems);
        std::swap(_world_components, other._world_components);
    }
    for(const ComponentTypeIndex c : _required_components) {
        unused(c);
        y_debug_assert(find_container(c));
    }
}

void EntityWorld::tick() {
    y_profile();
    for(auto& system : _systems) {
        y_profile_dyn_zone(system->name().data());
        system->tick(*this);
    }
    for(auto& container : _containers) {
        if(container) {
            container->clear_recent();
        }
    }
}

void EntityWorld::update(float dt) {
    y_profile();
    for(auto& system : _systems) {
        y_profile_dyn_zone(system->name().data());
        system->update(*this, dt);
    }
}

usize EntityWorld::entity_count() const {
    return _entities.size();
}

bool EntityWorld::exists(EntityId id) const {
    return _entities.contains(id);
}

EntityId EntityWorld::create_entity() {
    const EntityId id = _entities.create();
    for(const ComponentTypeIndex c : _required_components) {
        ComponentContainerBase* container = find_container(c);
        y_debug_assert(container && container->type_id() == c);
        container->add(*this, id);
    }
    return id;
}

EntityId EntityWorld::create_entity(const Archetype& archetype) {
    const EntityId id = create_entity();
    for(const auto& info : archetype.component_infos()) {
        ComponentContainerBase* cont = find_or_create_container(info);
        cont->add(*this, id);
    }
    return id;
}

EntityId EntityWorld::create_entity(const EntityPrefab& prefab) {
    const EntityId id = create_entity();
    for(const auto& comp : prefab.components()) {
        if(!comp) {
            log_msg("Unable to add null component", Log::Error);
        } else {
            comp->add_to(*this, id);
        }
    }
    return id;
}

void EntityWorld::remove_entity(EntityId id) {
    check_exists(id);
    for(auto& container : _containers) {
        if(container) {
            container->remove(id);
        }
    }
    _entities.recycle(id);
}

EntityId EntityWorld::id_from_index(u32 index) const {
    return _entities.id_from_index(index);
}

EntityPrefab EntityWorld::create_prefab(EntityId id) const {
    check_exists(id);
    EntityPrefab prefab;
    for(auto& container : _containers) {
        if(container) {
            if(!container->contains(id)) {
                continue;
            }
            auto box = container->create_box(id);
            if(!box) {
                log_msg(fmt("% is not copyable and was excluded from prefab", container->runtime_info().type_name), Log::Warning);
            }
            prefab.add(std::move(box));
        }
    }
    return prefab;
}

core::Span<EntityId> EntityWorld::component_ids(ComponentTypeIndex type_id) const {
    const ComponentContainerBase* cont = find_container(type_id);
    return cont ? cont->ids() : core::Span<EntityId>();
}

core::Span<EntityId> EntityWorld::recently_added(ComponentTypeIndex type_id) const {
    const ComponentContainerBase* cont = find_container(type_id);
    return cont ? cont->recently_added() : core::Span<EntityId>();
}

core::Span<EntityId> EntityWorld::with_tag(const core::String& tag) const {
    const SparseIdSetBase* set = tag_set(tag);
    return set ? set->ids() : core::Span<EntityId>();
}

const SparseIdSet* EntityWorld::raw_tag_set(const core::String& tag) const {
    if(const auto it = _tags.find(tag); it != _tags.end()) {
        return &it->second;
    }
    return nullptr;
}

const SparseIdSetBase* EntityWorld::tag_set(const core::String& tag) const {
    if(tag.is_empty()) {
        return nullptr;
    }

    if(tag.starts_with("#")) {
        for(const auto& container : _containers) {
            if(container->runtime_info().clean_component_name() == tag.sub_str(1)) {
                return &container->id_set();
            }
        }
        return nullptr;
    }

    if(tag.starts_with("#")) {
        y_fatal("Not supported");
    }

    return raw_tag_set(tag);
}

void EntityWorld::add_tag(EntityId id, const core::String& tag) {
    check_exists(id);
    y_always_assert(!is_tag_implicit(tag), "Implicit tags can't be added directly");
    _tags[tag].set(id);
}

void EntityWorld::remove_tag(EntityId id, const core::String& tag) {
    check_exists(id);
    y_always_assert(!is_tag_implicit(tag), "Implicit tags can't be removed directly");
    _tags[tag].erase(id);
}

bool EntityWorld::has_tag(EntityId id, const core::String& tag) const {
    check_exists(id);
    const SparseIdSetBase* set = tag_set(tag);
    return set ? set->contains(id) : false;
}

bool EntityWorld::is_tag_implicit(std::string_view tag) {
    return !tag.empty() && (tag[0] == '!' || tag[0] == '#');
}

core::Span<ComponentTypeIndex> EntityWorld::required_components() const {
    return _required_components;
}

std::string_view EntityWorld::component_type_name(ComponentTypeIndex type_id) const {
    const ComponentContainerBase* cont = find_container(type_id);
    return cont ? cont->runtime_info().clean_component_name() : "";
}

const ComponentContainerBase* EntityWorld::find_container(ComponentTypeIndex type_id) const {
    return _containers.size() <= type_id ? nullptr : _containers[type_id].get();
}

ComponentContainerBase* EntityWorld::find_container(ComponentTypeIndex type_id) {
    return _containers.size() <= type_id ? nullptr : _containers[type_id].get();
}

ComponentContainerBase* EntityWorld::find_or_create_container(const ComponentRuntimeInfo& info) {
    auto& cont = _containers[info.type_id];
    if(!cont) {
        cont = info.create_type_container();
    }
    y_debug_assert(cont);
    y_debug_assert(cont->type_id() == info.type_id);
    return cont.get();
}

void EntityWorld::check_exists(EntityId id) const {
    y_always_assert(exists(id), "Entity doesn't exists");
}

void EntityWorld::post_deserialize() {
    core::Vector<std::unique_ptr<ComponentContainerBase>> patched;
    for(auto& container : _containers) {
        if(container) {
            const ComponentTypeIndex id = container->type_id();
            patched.set_min_size(id + 1);
            patched[id] = std::move(container);
        }
    }
    _containers = std::move(patched);

    for(auto& system : _systems) {
        y_debug_assert(system);
        system->reset(*this);
    }

    for(const ComponentTypeIndex c : _required_components) {
        unused(c);
        y_debug_assert(find_container(c));
    }
}

}
}

<commit_msg>Changed # to @ in implicit tags to avoid confusion in Lua<commit_after>/*******************************
Copyright (c) 2016-2022 Gr�goire Angerand

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

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

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

#include "EntityWorld.h"

#include <y/utils/log.h>
#include <y/utils/format.h>

#include <yave/assets/AssetLoadingContext.h>

namespace yave {
namespace ecs {

EntityWorld::EntityWorld() {
}

EntityWorld::~EntityWorld() {
    for(auto& system : _systems) {
        system->destroy(*this);
    }
    _containers.clear();
}

EntityWorld::EntityWorld(EntityWorld&& other) {
    swap(other);
}

EntityWorld& EntityWorld::operator=(EntityWorld&& other) {
    swap(other);
    return *this;
}

void EntityWorld::swap(EntityWorld& other) {
    if(this != &other) {
        std::swap(_containers, other._containers);
        std::swap(_tags, other._tags);
        std::swap(_entities, other._entities);
        std::swap(_required_components, other._required_components);
        std::swap(_systems, other._systems);
        std::swap(_world_components, other._world_components);
    }
    for(const ComponentTypeIndex c : _required_components) {
        unused(c);
        y_debug_assert(find_container(c));
    }
}

void EntityWorld::tick() {
    y_profile();
    for(auto& system : _systems) {
        y_profile_dyn_zone(system->name().data());
        system->tick(*this);
    }
    for(auto& container : _containers) {
        if(container) {
            container->clear_recent();
        }
    }
}

void EntityWorld::update(float dt) {
    y_profile();
    for(auto& system : _systems) {
        y_profile_dyn_zone(system->name().data());
        system->update(*this, dt);
    }
}

usize EntityWorld::entity_count() const {
    return _entities.size();
}

bool EntityWorld::exists(EntityId id) const {
    return _entities.contains(id);
}

EntityId EntityWorld::create_entity() {
    const EntityId id = _entities.create();
    for(const ComponentTypeIndex c : _required_components) {
        ComponentContainerBase* container = find_container(c);
        y_debug_assert(container && container->type_id() == c);
        container->add(*this, id);
    }
    return id;
}

EntityId EntityWorld::create_entity(const Archetype& archetype) {
    const EntityId id = create_entity();
    for(const auto& info : archetype.component_infos()) {
        ComponentContainerBase* cont = find_or_create_container(info);
        cont->add(*this, id);
    }
    return id;
}

EntityId EntityWorld::create_entity(const EntityPrefab& prefab) {
    const EntityId id = create_entity();
    for(const auto& comp : prefab.components()) {
        if(!comp) {
            log_msg("Unable to add null component", Log::Error);
        } else {
            comp->add_to(*this, id);
        }
    }
    return id;
}

void EntityWorld::remove_entity(EntityId id) {
    check_exists(id);
    for(auto& container : _containers) {
        if(container) {
            container->remove(id);
        }
    }
    _entities.recycle(id);
}

EntityId EntityWorld::id_from_index(u32 index) const {
    return _entities.id_from_index(index);
}

EntityPrefab EntityWorld::create_prefab(EntityId id) const {
    check_exists(id);
    EntityPrefab prefab;
    for(auto& container : _containers) {
        if(container) {
            if(!container->contains(id)) {
                continue;
            }
            auto box = container->create_box(id);
            if(!box) {
                log_msg(fmt("% is not copyable and was excluded from prefab", container->runtime_info().type_name), Log::Warning);
            }
            prefab.add(std::move(box));
        }
    }
    return prefab;
}

core::Span<EntityId> EntityWorld::component_ids(ComponentTypeIndex type_id) const {
    const ComponentContainerBase* cont = find_container(type_id);
    return cont ? cont->ids() : core::Span<EntityId>();
}

core::Span<EntityId> EntityWorld::recently_added(ComponentTypeIndex type_id) const {
    const ComponentContainerBase* cont = find_container(type_id);
    return cont ? cont->recently_added() : core::Span<EntityId>();
}

core::Span<EntityId> EntityWorld::with_tag(const core::String& tag) const {
    const SparseIdSetBase* set = tag_set(tag);
    return set ? set->ids() : core::Span<EntityId>();
}

const SparseIdSet* EntityWorld::raw_tag_set(const core::String& tag) const {
    if(const auto it = _tags.find(tag); it != _tags.end()) {
        return &it->second;
    }
    return nullptr;
}

const SparseIdSetBase* EntityWorld::tag_set(const core::String& tag) const {
    if(tag.is_empty()) {
        return nullptr;
    }

    if(tag[0] == '@') {
        for(const auto& container : _containers) {
            if(container->runtime_info().clean_component_name() == tag.sub_str(1)) {
                return &container->id_set();
            }
        }
        return nullptr;
    }

    if(tag[0] == '!') {
        y_fatal("Not supported");
    }

    return raw_tag_set(tag);
}

void EntityWorld::add_tag(EntityId id, const core::String& tag) {
    check_exists(id);
    y_always_assert(!is_tag_implicit(tag), "Implicit tags can't be added directly");
    _tags[tag].set(id);
}

void EntityWorld::remove_tag(EntityId id, const core::String& tag) {
    check_exists(id);
    y_always_assert(!is_tag_implicit(tag), "Implicit tags can't be removed directly");
    _tags[tag].erase(id);
}

bool EntityWorld::has_tag(EntityId id, const core::String& tag) const {
    check_exists(id);
    const SparseIdSetBase* set = tag_set(tag);
    return set ? set->contains(id) : false;
}

bool EntityWorld::is_tag_implicit(std::string_view tag) {
    return !tag.empty() && (tag[0] == '@' || tag[0] == '@');
}

core::Span<ComponentTypeIndex> EntityWorld::required_components() const {
    return _required_components;
}

std::string_view EntityWorld::component_type_name(ComponentTypeIndex type_id) const {
    const ComponentContainerBase* cont = find_container(type_id);
    return cont ? cont->runtime_info().clean_component_name() : "";
}

const ComponentContainerBase* EntityWorld::find_container(ComponentTypeIndex type_id) const {
    return _containers.size() <= type_id ? nullptr : _containers[type_id].get();
}

ComponentContainerBase* EntityWorld::find_container(ComponentTypeIndex type_id) {
    return _containers.size() <= type_id ? nullptr : _containers[type_id].get();
}

ComponentContainerBase* EntityWorld::find_or_create_container(const ComponentRuntimeInfo& info) {
    auto& cont = _containers[info.type_id];
    if(!cont) {
        cont = info.create_type_container();
    }
    y_debug_assert(cont);
    y_debug_assert(cont->type_id() == info.type_id);
    return cont.get();
}

void EntityWorld::check_exists(EntityId id) const {
    y_always_assert(exists(id), "Entity doesn't exists");
}

void EntityWorld::post_deserialize() {
    core::Vector<std::unique_ptr<ComponentContainerBase>> patched;
    for(auto& container : _containers) {
        if(container) {
            const ComponentTypeIndex id = container->type_id();
            patched.set_min_size(id + 1);
            patched[id] = std::move(container);
        }
    }
    _containers = std::move(patched);

    for(auto& system : _systems) {
        y_debug_assert(system);
        system->reset(*this);
    }

    for(const ComponentTypeIndex c : _required_components) {
        unused(c);
        y_debug_assert(find_container(c));
    }
}

}
}

<|endoftext|>


<commit_before>/*
  RTQL8, Copyright (c) 2011 Georgia Tech Graphics Lab
  All rights reserved.

  Author	Sehoon Ha
  Date		06/12/2011
*/

#include "Skeleton.h"

#include <cassert>
using namespace std;
using namespace Eigen;

#include "Dof.h"
#include "Joint.h"
#include "BodyNode.h"
#include "Marker.h"
#include "Transformation.h"

#include "renderer/OpenGLRenderInterface.h"

namespace model3d {

    Skeleton::Skeleton() {
        mMass = 0;
    }

    Skeleton::~Skeleton(){
        for(int i = 0; i < mJoints.size(); i++) delete mJoints[i];
        mJoints.clear();
        mDofs.clear();
        mTransforms.clear();
        for(int i=0; i<mNodes.size(); i++) delete mNodes[i];
        mNodes.clear();
        mHandles.clear();
    }

    void Skeleton::addHandle(Marker *_h) {
        mHandles.push_back(_h);
        _h->setModelIndex(mHandles.size()-1);
        BodyNode *body = _h->getNode();
        body->addHandle(_h);
    }

    void Skeleton::addNode(BodyNode *b) {
        mNodes.push_back(b);
        b->setModelIndex(mNodes.size()-1);
        addJoint(b->getJointIn());
    }

    void Skeleton::addJoint(Joint *_j) {
        mJoints.push_back(_j);
        _j->setModelIndex(mJoints.size()-1);
    }

    void Skeleton::addDof(Dof *q) {
        mDofs.push_back(q);
        q->setModelIndex(mDofs.size()-1);
        q->setVariable();
    }

    void Skeleton::addTransform(Transformation *t) {
        mTransforms.push_back(t);
        t->setVariable(true);
        t->setModelIndex(mTransforms.size()-1);
        for(int i=0; i<t->getNumDofs(); i++) {
            addDof(t->getDof(i));
        }
    }

    void Skeleton::initSkel() {
        mRoot = mNodes[0];
        nDofs = mDofs.size();
        nNodes = mNodes.size();
        nHandles = mHandles.size();

        // calculate mass
        // init the dependsOnDof stucture for each bodylink
        for(int i=0; i<nNodes; i++) {
            mNodes[i]->setModel(this);
            mNodes[i]->setDependDofMap(nDofs);
            mNodes.at(i)->init();
            mMass += mNodes[i]->getMass();
        }

        mCurrState = VectorXd::Zero(nDofs);

        for(int i=0; i<nDofs; i++)
            mCurrState[i] = mDofs.at(i)->getValue();
        for(int i=0; i<nNodes; i++)
            mNodes.at(i)->updateTransform();
    }

    BodyNode* Skeleton::getNode(const char* const name) {
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++){
            BodyNode* node = getNode(i);
            if (strcmp(name, node->getName()) == 0) {
                return node;
            }
        }
        return NULL;
    }

    int Skeleton::getNodeIndex(const char* const name) {
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++){
            BodyNode* node = getNode(i);
            if (strcmp(name, node->getName()) == 0) {
                return i;
            }
        }
        return -1;
    }

    void Skeleton::setState(const VectorXd& state) {
        assert(state.size() == nDofs);
        int k=0;
        for(k=0; k<nDofs; k++)
            if(mCurrState[k]!=state[k]) break;
        if(k==nDofs) return;

        mCurrState = state;
        for(int i=0; i<nDofs; i++)
            mDofs.at(i)->setValue(state[i]);
        for(int i=0; i<nNodes; i++)
            mNodes.at(i)->updateTransform();
    }

    void Skeleton::setState(const vector<double>& state) {
        assert(state.size()==nDofs);
        int k=0;
        for(k=0; k<nDofs; k++)
            if(mCurrState[k]!=state.at(k)) break;
        if(k==nDofs) return;

        for(int i=0; i<nDofs; i++){
            mDofs.at(i)->setValue(state.at(i));
            mCurrState[k] = state.at(i);
        }
        for(int i=0; i<nNodes; i++)
            mNodes.at(i)->updateTransform();
    }

    void Skeleton::setPose(const VectorXd& _pose){
#ifdef DEBUG
        assert(_pose.size() == nDofs);
#endif
        for(int i=0; i<nDofs; i++)
            mDofs[i]->setValue(_pose(i));
    }

    void Skeleton::setPose(const vector<double>& _pose){
#ifdef DEBUG
        assert(_pose.size() == nDofs);
#endif
        for(int i=0; i<nDofs; i++)
            mDofs[i]->setValue(_pose[i]);
    }

    void Skeleton::draw(Renderer::OpenGLRenderInterface* RI, const Vector4d& _color, bool _default)
    {
        mRoot->draw(RI, _color, _default);
    }
    void Skeleton::drawHandles(Renderer::OpenGLRenderInterface* RI, const Vector4d& _color, bool _default)
    {
        mRoot->drawHandles(RI, _color, _default);
    }

} // namespace model3d
<commit_msg>fix a small typo<commit_after>/*
  RTQL8, Copyright (c) 2011 Georgia Tech Graphics Lab
  All rights reserved.

  Author	Sehoon Ha
  Date		06/12/2011
*/

#include "Skeleton.h"

#include <cassert>
using namespace std;
using namespace Eigen;

#include "Dof.h"
#include "Joint.h"
#include "BodyNode.h"
#include "Marker.h"
#include "Transformation.h"

#include "renderer/OpenGLRenderInterface.h"

namespace model3d {

    Skeleton::Skeleton() {
        mMass = 0;
    }

    Skeleton::~Skeleton(){
        for(int i = 0; i < mJoints.size(); i++) delete mJoints[i];
        mJoints.clear();
        mDofs.clear();
        mTransforms.clear();
        for(int i=0; i<mNodes.size(); i++) delete mNodes[i];
        mNodes.clear();
        mHandles.clear();
    }

    void Skeleton::addHandle(Marker *_h) {
        mHandles.push_back(_h);
        _h->setModelIndex(mHandles.size()-1);
        BodyNode *body = _h->getNode();
        body->addHandle(_h);
    }

    void Skeleton::addNode(BodyNode *b) {
        mNodes.push_back(b);
        b->setModelIndex(mNodes.size()-1);
        addJoint(b->getJointIn());
    }

    void Skeleton::addJoint(Joint *_j) {
        mJoints.push_back(_j);
        _j->setModelIndex(mJoints.size()-1);
    }

    void Skeleton::addDof(Dof *q) {
        mDofs.push_back(q);
        q->setModelIndex(mDofs.size()-1);
        q->setVariable();
    }

    void Skeleton::addTransform(Transformation *t) {
        mTransforms.push_back(t);
        t->setVariable(true);
        t->setModelIndex(mTransforms.size()-1);
        for(int i=0; i<t->getNumDofs(); i++) {
            addDof(t->getDof(i));
        }
    }

    void Skeleton::initSkel() {
        mRoot = mNodes[0];
        nDofs = mDofs.size();
        nNodes = mNodes.size();
        nHandles = mHandles.size();

        // calculate mass
        // init the dependsOnDof stucture for each bodylink
        for(int i=0; i<nNodes; i++) {
            mNodes[i]->setModel(this);
            mNodes[i]->setDependDofMap(nDofs);
            mNodes.at(i)->init();
            mMass += mNodes[i]->getMass();
        }

        mCurrState = VectorXd::Zero(nDofs);

        for(int i=0; i<nDofs; i++)
            mCurrState[i] = mDofs.at(i)->getValue();
        for(int i=0; i<nNodes; i++)
            mNodes.at(i)->updateTransform();
    }

    BodyNode* Skeleton::getNode(const char* const name) {
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++){
            BodyNode* node = getNode(i);
            if (strcmp(name, node->getName()) == 0) {
                return node;
            }
        }
        return NULL;
    }

    int Skeleton::getNodeIndex(const char* const name) {
        const int nNodes = getNumNodes();
        for(int i = 0; i < nNodes; i++){
            BodyNode* node = getNode(i);
            if (strcmp(name, node->getName()) == 0) {
                return i;
            }
        }
        return -1;
    }

    void Skeleton::setState(const VectorXd& state) {
        assert(state.size() == nDofs);
        int k=0;
        for(k=0; k<nDofs; k++)
            if(mCurrState[k]!=state[k]) break;
        if(k==nDofs) return;

        mCurrState = state;
        for(int i=0; i<nDofs; i++)
            mDofs.at(i)->setValue(state[i]);
        for(int i=0; i<nNodes; i++)
            mNodes.at(i)->updateTransform();
    }

    void Skeleton::setState(const vector<double>& state) {
        assert(state.size()==nDofs);
        int k=0;
        for(k=0; k<nDofs; k++)
            if(mCurrState[k]!=state.at(k)) break;
        if(k==nDofs) return;

        for(int i=0; i<nDofs; i++){
            mDofs.at(i)->setValue(state.at(i));
            mCurrState[i] = state.at(i);
        }
        for(int i=0; i<nNodes; i++)
            mNodes.at(i)->updateTransform();
    }

    void Skeleton::setPose(const VectorXd& _pose){
#ifdef DEBUG
        assert(_pose.size() == nDofs);
#endif
        for(int i=0; i<nDofs; i++)
            mDofs[i]->setValue(_pose(i));
    }

    void Skeleton::setPose(const vector<double>& _pose){
#ifdef DEBUG
        assert(_pose.size() == nDofs);
#endif
        for(int i=0; i<nDofs; i++)
            mDofs[i]->setValue(_pose[i]);
    }

    void Skeleton::draw(Renderer::OpenGLRenderInterface* RI, const Vector4d& _color, bool _default)
    {
        mRoot->draw(RI, _color, _default);
    }
    void Skeleton::drawHandles(Renderer::OpenGLRenderInterface* RI, const Vector4d& _color, bool _default)
    {
        mRoot->drawHandles(RI, _color, _default);
    }

} // namespace model3d
<|endoftext|>


<commit_before>/*
A positive integer D is a factor of a positive integer N if there exists an integer M such that N = D * M.
For example, 6 is a factor of 24, because M = 4 satisfies the above condition (24 = 6 * 4).
Write a function:
int solution(int N);
that, given a positive integer N, returns the number of its factors.
For example, given N = 24, the function should return 8, because 24 has 8 factors, namely 1, 2, 3, 4, 6, 8, 12, 24. There are no other factors of 24.
Assume that:
N is an integer within the range [1..2,147,483,647].
Complexity:
expected worst-case time complexity is O(sqrt(N));
expected worst-case space complexity is O(1).
Copyright 2009–2015 by Codility Limited. All Rights Reserved. Unauthorized copying, publication or disclosure prohibited.
*/
<commit_msg>Update solution.cpp<commit_after>// you can use includes, for example:
#include <algorithm>

// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;

int solution(int N) {
    // write your code in C++11
    float sqrt_N = sqrt(N);
    int count(0);
    for(int a=floor(sqrt_N); a>0; a--) {
        if( N%a==0 ) {
            count++;
        }
    }
    if( N==floor(sqrt_N)*floor(sqrt_N) )
        return 2*count-1;
    else
        return 2*count;
}
<|endoftext|>