<commit_before>/* The MIT License
 *
 * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
 *
 * 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 <prerequisites.h>
#include <core/resources.h>
#include <core/platform.h>

#include <physfs.h>

Resources g_resources;

void Resources::init(const char *argv0)
{
    PHYSFS_init(argv0);

    // try to find data directory
    std::list<std::string> searchPaths;
    std::string dir;
    std::string baseDir = PHYSFS_getBaseDir();

    std::list<std::string> possibleDirs;
    possibleDirs.push_back("data");
    possibleDirs.push_back(baseDir + "data");
    possibleDirs.push_back(baseDir + "../data");
    possibleDirs.push_back(baseDir + "../share/data");
    possibleDirs.push_back("");

    foreach(dir, possibleDirs)
        if(g_resources.addToSearchPath(dir))
            break;

    // setup write directory
    dir = Platform::getAppUserDir();
    if(g_resources.setWriteDir(dir))
        g_resources.addToSearchPath(dir);
    else
        logError("ERROR: could not setup write directory");
}

void Resources::terminate()
{
    PHYSFS_deinit();
}

bool Resources::setWriteDir(const std::string& path)
{
    if(!PHYSFS_setWriteDir(path.c_str()))
        return false;
    return true;
}

bool Resources::addToSearchPath(const std::string& path, bool insertInFront /*= true*/)
{
    if(!PHYSFS_addToSearchPath(path.c_str(), insertInFront ? 0 : 1))
        return false;
    return true;
}

void Resources::addPackagesToSearchPath(const std::string &packagesDirectory, const std::string &packageExtension, bool append)
{
    auto files = listDirectoryFiles(resolvePath(packagesDirectory));
    foreach(const std::string& file, files) {
        if(boost::ends_with(file, packageExtension))
            addToSearchPath(packagesDirectory + "/" + file, !append);
    }
}

bool Resources::fileExists(const std::string& fileName)
{
    return (PHYSFS_exists(resolvePath(fileName).c_str()) && !PHYSFS_isDirectory(resolvePath(fileName).c_str()));
}

bool Resources::directoryExists(const std::string& directoryName)
{
    return (PHYSFS_exists(resolvePath(directoryName).c_str()) && PHYSFS_isDirectory(resolvePath(directoryName).c_str()));
}

bool Resources::loadFile(const std::string& fileName, std::iostream& out)
{
    out.clear(std::ios::goodbit);
    PHYSFS_file *file = PHYSFS_openRead(resolvePath(fileName).c_str());
    if(!file) {
        flogError("ERROR: Failed to load file \"%s\": %s", fileName.c_str() % PHYSFS_getLastError());
        out.clear(std::ios::failbit);
        return false;
    } else {
        int fileSize = PHYSFS_fileLength(file);
        if(fileSize > 0) {
            char *buffer = new char[fileSize];
            PHYSFS_read(file, (void*)buffer, 1, fileSize);
            out.write(buffer, fileSize);
            delete buffer;
        } else
            out.clear(std::ios::eofbit);
        PHYSFS_close(file);
        out.seekg(0, std::ios::beg);
        return true;
    }
}

bool Resources::saveFile(const std::string &fileName, const uchar *data, uint size)
{
    PHYSFS_file *file = PHYSFS_openWrite(resolvePath(fileName).c_str());
    if(!file) {
        flogError("ERROR: Failed to save file \"%s\": %s", fileName.c_str() % PHYSFS_getLastError());
        return false;
    }

    PHYSFS_write(file, (void*)data, size, 1);
    PHYSFS_close(file);
    return true;
}

bool Resources::saveFile(const std::string &fileName, std::istream& in)
{
    std::streampos oldPos = in.tellg();
    in.seekg(0, std::ios::end);
    std::streampos size = in.tellg();
    in.seekg(0, std::ios::beg);
    char *buffer = new char[size];
    in.read(buffer, size);
    bool ret = saveFile(fileName, (const uchar*)buffer, size);
    delete[] buffer;
    in.seekg(oldPos, std::ios::beg);
    return ret;
}

bool Resources::deleteFile(const std::string& fileName)
{
    return PHYSFS_delete(resolvePath(fileName).c_str()) != 0;
}

std::list<std::string> Resources::listDirectoryFiles(const std::string& directoryPath)
{
    std::list<std::string> files;
    char **rc = PHYSFS_enumerateFiles(resolvePath(directoryPath).c_str());

    for(char **i = rc; *i != NULL; i++)
        files.push_back(*i);

    PHYSFS_freeList(rc);
    return files;
}

void Resources::pushCurrentPath(const std::string &currentPath)
{
    m_currentPaths.push(currentPath);
}

void Resources::popCurrentPath()
{
    m_currentPaths.pop();
}

std::string Resources::resolvePath(const std::string& path)
{
    std::string fullPath;
    if(boost::starts_with(path, "/"))
        fullPath = path.substr(1);
    else {
        if(m_currentPaths.size() > 0) {
            std::string currentPath = m_currentPaths.top();
            if(currentPath.length() > 0)
                fullPath += currentPath + "/";
        }
        fullPath += path;
    }
    return fullPath;
}

<commit_msg>rework on resources system<commit_after>/* The MIT License
 *
 * Copyright (c) 2010 OTClient, https://github.com/edubart/otclient
 *
 * 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 <prerequisites.h>
#include <core/resources.h>
#include <core/platform.h>

#include <physfs.h>

Resources g_resources;

void Resources::init(const char *argv0)
{
    PHYSFS_init(argv0);

    // try to find data directory
    std::list<std::string> searchPaths;
    std::string dir;
    std::string baseDir = PHYSFS_getBaseDir();

    std::list<std::string> possibleDirs;
    possibleDirs.push_back("data");
    possibleDirs.push_back(baseDir + "data");
    possibleDirs.push_back(baseDir + "../data");
    possibleDirs.push_back(baseDir + "../share/otclient/data");
    possibleDirs.push_back("");

    bool found = false;
    foreach(dir, possibleDirs) {
        if(g_resources.addToSearchPath(dir)) {
            flogInfo("Using data directory: %s", dir.c_str());
            found = true;
            break;
        }
    }
    if(!found)
        logFatal("ERROR: could not find data directory");

    // setup write directory
    dir = Platform::getAppUserDir();
    if(g_resources.setWriteDir(dir))
        g_resources.addToSearchPath(dir);
    else
        logError("ERROR: could not setup write directory");
}

void Resources::terminate()
{
    PHYSFS_deinit();
}

bool Resources::setWriteDir(const std::string& path)
{
    if(!PHYSFS_setWriteDir(path.c_str()))
        return false;
    return true;
}

bool Resources::addToSearchPath(const std::string& path, bool insertInFront /*= true*/)
{
    if(!PHYSFS_addToSearchPath(path.c_str(), insertInFront ? 0 : 1))
        return false;
    return true;
}

void Resources::addPackagesToSearchPath(const std::string &packagesDirectory, const std::string &packageExtension, bool append)
{
    auto files = listDirectoryFiles(resolvePath(packagesDirectory));
    foreach(const std::string& file, files) {
        if(boost::ends_with(file, packageExtension))
            addToSearchPath(packagesDirectory + "/" + file, !append);
    }
}

bool Resources::fileExists(const std::string& fileName)
{
    return (PHYSFS_exists(resolvePath(fileName).c_str()) && !PHYSFS_isDirectory(resolvePath(fileName).c_str()));
}

bool Resources::directoryExists(const std::string& directoryName)
{
    return (PHYSFS_exists(resolvePath(directoryName).c_str()) && PHYSFS_isDirectory(resolvePath(directoryName).c_str()));
}

bool Resources::loadFile(const std::string& fileName, std::iostream& out)
{
    out.clear(std::ios::goodbit);
    PHYSFS_file *file = PHYSFS_openRead(resolvePath(fileName).c_str());
    if(!file) {
        flogError("ERROR: Failed to load file \"%s\": %s", fileName.c_str() % PHYSFS_getLastError());
        out.clear(std::ios::failbit);
        return false;
    } else {
        int fileSize = PHYSFS_fileLength(file);
        if(fileSize > 0) {
            char *buffer = new char[fileSize];
            PHYSFS_read(file, (void*)buffer, 1, fileSize);
            out.write(buffer, fileSize);
            delete buffer;
        } else
            out.clear(std::ios::eofbit);
        PHYSFS_close(file);
        out.seekg(0, std::ios::beg);
        return true;
    }
}

bool Resources::saveFile(const std::string &fileName, const uchar *data, uint size)
{
    PHYSFS_file *file = PHYSFS_openWrite(resolvePath(fileName).c_str());
    if(!file) {
        flogError("ERROR: Failed to save file \"%s\": %s", fileName.c_str() % PHYSFS_getLastError());
        return false;
    }

    PHYSFS_write(file, (void*)data, size, 1);
    PHYSFS_close(file);
    return true;
}

bool Resources::saveFile(const std::string &fileName, std::istream& in)
{
    std::streampos oldPos = in.tellg();
    in.seekg(0, std::ios::end);
    std::streampos size = in.tellg();
    in.seekg(0, std::ios::beg);
    char *buffer = new char[size];
    in.read(buffer, size);
    bool ret = saveFile(fileName, (const uchar*)buffer, size);
    delete[] buffer;
    in.seekg(oldPos, std::ios::beg);
    return ret;
}

bool Resources::deleteFile(const std::string& fileName)
{
    return PHYSFS_delete(resolvePath(fileName).c_str()) != 0;
}

std::list<std::string> Resources::listDirectoryFiles(const std::string& directoryPath)
{
    std::list<std::string> files;
    char **rc = PHYSFS_enumerateFiles(resolvePath(directoryPath).c_str());

    for(char **i = rc; *i != NULL; i++)
        files.push_back(*i);

    PHYSFS_freeList(rc);
    return files;
}

void Resources::pushCurrentPath(const std::string &currentPath)
{
    m_currentPaths.push(currentPath);
}

void Resources::popCurrentPath()
{
    m_currentPaths.pop();
}

std::string Resources::resolvePath(const std::string& path)
{
    std::string fullPath;
    if(boost::starts_with(path, "/"))
        fullPath = path.substr(1);
    else {
        if(m_currentPaths.size() > 0) {
            std::string currentPath = m_currentPaths.top();
            if(currentPath.length() > 0)
                fullPath += currentPath + "/";
        }
        fullPath += path;
    }
    return fullPath;
}

<|endoftext|>


<commit_before>#include "IMPCacher.h"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Instructions.h"
#include "llvm/Constants.h"
#include "llvm/LLVMContext.h"
#include "llvm/Metadata.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"

#include "LLVMCompat.h"

GNUstep::IMPCacher::IMPCacher(LLVMContext &C, Pass *owner) : Context(C),
  Owner(owner) {

  PtrTy = Type::getInt8PtrTy(Context);
  IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(C) : Type::getInt64Ty(C);
  IdTy = PointerType::getUnqual(PtrTy);
  Value *AlreadyCachedFlagValue = MDString::get(C, "IMPCached");
  AlreadyCachedFlag = CreateMDNode(C, AlreadyCachedFlagValue);
  IMPCacheFlagKind = Context.getMDKindID("IMPCache");
}

void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
    *version, bool isSuperMessage) {

  // If this IMP is already cached, don't cache it again.
  if (lookup->getMetadata(IMPCacheFlagKind)) { return; }

  lookup->setMetadata(IMPCacheFlagKind, AlreadyCachedFlag);

  BasicBlock *beforeLookupBB = lookup->getParent();
  BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, Owner);
  BasicBlock::iterator iter = lookup;
  iter++;
  BasicBlock *afterLookupBB = SplitBlock(iter->getParent(), iter, Owner);

  removeTerminator(beforeLookupBB);

  IRBuilder<> B = IRBuilder<>(beforeLookupBB);
  // Load the slot and check that neither it nor the version is 0.
  Value *slotValue = B.CreateLoad(slot);
  Value *versionValue = B.CreateLoad(version);
  Value *receiverPtr = lookup->getOperand(0);
  Value *receiver = receiverPtr;
  if (!isSuperMessage) {
    receiver = B.CreateLoad(receiverPtr);
  }

  Value *isCacheEmpty =
    B.CreateICmpEQ(versionValue, Constant::getNullValue(IntTy));
  Value *receiverNotNil =
     B.CreateICmpNE(receiver, Constant::getNullValue(receiver->getType()));
  isCacheEmpty = B.CreateAnd(isCacheEmpty, receiverNotNil);

  BasicBlock *cacheLookupBB = BasicBlock::Create(Context, "cache_check",
      lookupBB->getParent());

  B.CreateCondBr(isCacheEmpty, lookupBB, cacheLookupBB);

  // Check the cache node is current
  B.SetInsertPoint(cacheLookupBB);
  Value *slotVersion = B.CreateStructGEP(slotValue, 3);
  // Note: Volatile load because the slot version might have changed in
  // another thread.
  slotVersion = B.CreateLoad(slotVersion, true, "slot_version");
  Value *slotCachedFor = B.CreateStructGEP(slotValue, 1);
  slotCachedFor = B.CreateLoad(slotCachedFor, true, "slot_owner");
  Value *cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
  Value *isVersionCorrect = B.CreateICmpEQ(slotVersion, versionValue);
  Value *isOwnerCorrect = B.CreateICmpEQ(slotCachedFor, cls);
  Value *isSlotValid = B.CreateAnd(isVersionCorrect, isOwnerCorrect);
  // If this slot is still valid, skip the lookup.
  B.CreateCondBr(isSlotValid, afterLookupBB, lookupBB);

  // Replace the looked up slot with the loaded one
  B.SetInsertPoint(afterLookupBB, afterLookupBB->begin());
  // Not volatile, so a redundant load elimination pass can do some phi
  // magic with this later.
  lookup->replaceAllUsesWith(B.CreateLoad(slot));

  // Perform the real lookup and cache the result
  removeTerminator(lookupBB);
  B.SetInsertPoint(lookupBB);
  Value * newReceiver = receiver;
  if (!isSuperMessage) {
    newReceiver = B.CreateLoad(receiverPtr);
  }
  BasicBlock *storeCacheBB = BasicBlock::Create(Context, "cache_store",
      lookupBB->getParent());

  // Don't store the cached lookup if we are doing forwarding tricks.
  B.CreateBr(storeCacheBB);
  /*
  B.CreateCondBr(B.CreateICmpEQ(receiver, newReceiver), storeCacheBB,
      afterLookupBB);
      */
  B.SetInsertPoint(storeCacheBB);

  // Store it even if the version is 0, because we always check that the
  // version is not 0 at the start and an occasional redundant store is
  // probably better than a branch every time.
  B.CreateStore(lookup, slot);
  //B.CreateStore(B.CreateLoad(B.CreateStructGEP(lookup, 3)), version);
  cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
  B.CreateStore(cls, B.CreateStructGEP(lookup, 1));
  B.CreateBr(afterLookupBB);
}

void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
    *function) {
  BasicBlock *beforeCallBB = call->getParent();
  BasicBlock *callBB = SplitBlock(beforeCallBB, call, Owner);
  BasicBlock *inlineBB = BasicBlock::Create(Context, "inline",
      callBB->getParent());

  BasicBlock::iterator iter = call;
  iter++;

  BasicBlock *afterCallBB = SplitBlock(iter->getParent(), iter, Owner);

  removeTerminator(beforeCallBB);

  // Put a branch before the call, testing whether the callee really is the
  // function
  IRBuilder<> B = IRBuilder<>(beforeCallBB);
  Value *callee = isa<CallInst>(call) ? cast<CallInst>(call)->getCalledValue()
      : cast<InvokeInst>(call)->getCalledValue();

  const FunctionType *FTy = function->getFunctionType();
  const FunctionType *calleeTy = cast<FunctionType>(
      cast<PointerType>(callee->getType())->getElementType());
  if (calleeTy != FTy) {
    callee = B.CreateBitCast(callee, function->getType());
  }

  Value *isInlineValid = B.CreateICmpEQ(callee, function);
  B.CreateCondBr(isInlineValid, inlineBB, callBB);

  // In the inline BB, add a copy of the call, but this time calling the real
  // version.
  Instruction *inlineCall = call->clone();
  Value *inlineResult= inlineCall;
  inlineBB->getInstList().push_back(inlineCall);

  B.SetInsertPoint(inlineBB);

  if (calleeTy != FTy) {
    for (unsigned i=0 ; i<FTy->getNumParams() ; i++) {
      const Type *callType = calleeTy->getParamType(i);
      const Type *argType = FTy->getParamType(i);
      if (callType != argType) {
        inlineCall->setOperand(i, new
            BitCastInst(inlineCall->getOperand(i), argType, "", inlineCall));
      }
    }
    if (FTy->getReturnType() != calleeTy->getReturnType()) {
      if (FTy->getReturnType() == Type::getVoidTy(Context)) {
        inlineResult = Constant::getNullValue(calleeTy->getReturnType());
      } else {
        inlineResult =
          new BitCastInst(inlineCall, calleeTy->getReturnType(), "", inlineBB);
      }
    }
  }

  B.CreateBr(afterCallBB);

  // Unify the return values
  if (call->getType() != Type::getVoidTy(Context)) {
    PHINode *phi = CreatePHI(call->getType(), 2, "", afterCallBB->begin());
    call->replaceAllUsesWith(phi);
    phi->addIncoming(call, callBB);
    phi->addIncoming(inlineResult, inlineBB);
  }

  // Really do the real inlining
  InlineFunctionInfo IFI(0, 0);
  if (CallInst *c = dyn_cast<CallInst>(inlineCall)) {
    c->setCalledFunction(function);
    InlineFunction(c, IFI);
  } else if (InvokeInst *c = dyn_cast<InvokeInst>(inlineCall)) {
    c->setCalledFunction(function);
    InlineFunction(c, IFI);
  }
}

// Cleanly removes a terminator instruction.
void GNUstep::removeTerminator(BasicBlock *BB) {
  TerminatorInst *BBTerm = BB->getTerminator();

  // Remove the BB as a predecessor from all of  successors
  for (unsigned i = 0, e = BBTerm->getNumSuccessors(); i != e; ++i) {
    BBTerm->getSuccessor(i)->removePredecessor(BB);
  }

  BBTerm->replaceAllUsesWith(UndefValue::get(BBTerm->getType()));
  // Remove the terminator instruction itself.
  BBTerm->eraseFromParent();
}
<commit_msg>Ooops.  Accidentally left the bit that actually did the optimisation commented out.<commit_after>#include "IMPCacher.h"
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Instructions.h"
#include "llvm/Constants.h"
#include "llvm/LLVMContext.h"
#include "llvm/Metadata.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"

#include "LLVMCompat.h"

GNUstep::IMPCacher::IMPCacher(LLVMContext &C, Pass *owner) : Context(C),
  Owner(owner) {

  PtrTy = Type::getInt8PtrTy(Context);
  IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(C) : Type::getInt64Ty(C);
  IdTy = PointerType::getUnqual(PtrTy);
  Value *AlreadyCachedFlagValue = MDString::get(C, "IMPCached");
  AlreadyCachedFlag = CreateMDNode(C, AlreadyCachedFlagValue);
  IMPCacheFlagKind = Context.getMDKindID("IMPCache");
}

void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
    *version, bool isSuperMessage) {

  // If this IMP is already cached, don't cache it again.
  if (lookup->getMetadata(IMPCacheFlagKind)) { return; }

  lookup->setMetadata(IMPCacheFlagKind, AlreadyCachedFlag);

  BasicBlock *beforeLookupBB = lookup->getParent();
  BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, Owner);
  BasicBlock::iterator iter = lookup;
  iter++;
  BasicBlock *afterLookupBB = SplitBlock(iter->getParent(), iter, Owner);

  removeTerminator(beforeLookupBB);

  IRBuilder<> B = IRBuilder<>(beforeLookupBB);
  // Load the slot and check that neither it nor the version is 0.
  Value *slotValue = B.CreateLoad(slot);
  Value *versionValue = B.CreateLoad(version);
  Value *receiverPtr = lookup->getOperand(0);
  Value *receiver = receiverPtr;
  if (!isSuperMessage) {
    receiver = B.CreateLoad(receiverPtr);
  }

  Value *isCacheEmpty =
    B.CreateICmpEQ(versionValue, Constant::getNullValue(IntTy));
  Value *receiverNotNil =
     B.CreateICmpNE(receiver, Constant::getNullValue(receiver->getType()));
  isCacheEmpty = B.CreateAnd(isCacheEmpty, receiverNotNil);

  BasicBlock *cacheLookupBB = BasicBlock::Create(Context, "cache_check",
      lookupBB->getParent());

  B.CreateCondBr(isCacheEmpty, lookupBB, cacheLookupBB);

  // Check the cache node is current
  B.SetInsertPoint(cacheLookupBB);
  Value *slotVersion = B.CreateStructGEP(slotValue, 3);
  // Note: Volatile load because the slot version might have changed in
  // another thread.
  slotVersion = B.CreateLoad(slotVersion, true, "slot_version");
  Value *slotCachedFor = B.CreateStructGEP(slotValue, 1);
  slotCachedFor = B.CreateLoad(slotCachedFor, true, "slot_owner");
  Value *cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
  Value *isVersionCorrect = B.CreateICmpEQ(slotVersion, versionValue);
  Value *isOwnerCorrect = B.CreateICmpEQ(slotCachedFor, cls);
  Value *isSlotValid = B.CreateAnd(isVersionCorrect, isOwnerCorrect);
  // If this slot is still valid, skip the lookup.
  B.CreateCondBr(isSlotValid, afterLookupBB, lookupBB);

  // Replace the looked up slot with the loaded one
  B.SetInsertPoint(afterLookupBB, afterLookupBB->begin());
  // Not volatile, so a redundant load elimination pass can do some phi
  // magic with this later.
  lookup->replaceAllUsesWith(B.CreateLoad(slot));

  // Perform the real lookup and cache the result
  removeTerminator(lookupBB);
  B.SetInsertPoint(lookupBB);
  Value * newReceiver = receiver;
  if (!isSuperMessage) {
    newReceiver = B.CreateLoad(receiverPtr);
  }
  BasicBlock *storeCacheBB = BasicBlock::Create(Context, "cache_store",
      lookupBB->getParent());

  // Don't store the cached lookup if we are doing forwarding tricks.
  B.CreateCondBr(B.CreateICmpEQ(receiver, newReceiver), storeCacheBB,
      afterLookupBB);
  B.SetInsertPoint(storeCacheBB);

  // Store it even if the version is 0, because we always check that the
  // version is not 0 at the start and an occasional redundant store is
  // probably better than a branch every time.
  B.CreateStore(lookup, slot);
  B.CreateStore(B.CreateLoad(B.CreateStructGEP(lookup, 3)), version);
  cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
  B.CreateStore(cls, B.CreateStructGEP(lookup, 1));
  B.CreateBr(afterLookupBB);
}

void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
    *function) {
  BasicBlock *beforeCallBB = call->getParent();
  BasicBlock *callBB = SplitBlock(beforeCallBB, call, Owner);
  BasicBlock *inlineBB = BasicBlock::Create(Context, "inline",
      callBB->getParent());

  BasicBlock::iterator iter = call;
  iter++;

  BasicBlock *afterCallBB = SplitBlock(iter->getParent(), iter, Owner);

  removeTerminator(beforeCallBB);

  // Put a branch before the call, testing whether the callee really is the
  // function
  IRBuilder<> B = IRBuilder<>(beforeCallBB);
  Value *callee = isa<CallInst>(call) ? cast<CallInst>(call)->getCalledValue()
      : cast<InvokeInst>(call)->getCalledValue();

  const FunctionType *FTy = function->getFunctionType();
  const FunctionType *calleeTy = cast<FunctionType>(
      cast<PointerType>(callee->getType())->getElementType());
  if (calleeTy != FTy) {
    callee = B.CreateBitCast(callee, function->getType());
  }

  Value *isInlineValid = B.CreateICmpEQ(callee, function);
  B.CreateCondBr(isInlineValid, inlineBB, callBB);

  // In the inline BB, add a copy of the call, but this time calling the real
  // version.
  Instruction *inlineCall = call->clone();
  Value *inlineResult= inlineCall;
  inlineBB->getInstList().push_back(inlineCall);

  B.SetInsertPoint(inlineBB);

  if (calleeTy != FTy) {
    for (unsigned i=0 ; i<FTy->getNumParams() ; i++) {
      const Type *callType = calleeTy->getParamType(i);
      const Type *argType = FTy->getParamType(i);
      if (callType != argType) {
        inlineCall->setOperand(i, new
            BitCastInst(inlineCall->getOperand(i), argType, "", inlineCall));
      }
    }
    if (FTy->getReturnType() != calleeTy->getReturnType()) {
      if (FTy->getReturnType() == Type::getVoidTy(Context)) {
        inlineResult = Constant::getNullValue(calleeTy->getReturnType());
      } else {
        inlineResult =
          new BitCastInst(inlineCall, calleeTy->getReturnType(), "", inlineBB);
      }
    }
  }

  B.CreateBr(afterCallBB);

  // Unify the return values
  if (call->getType() != Type::getVoidTy(Context)) {
    PHINode *phi = CreatePHI(call->getType(), 2, "", afterCallBB->begin());
    call->replaceAllUsesWith(phi);
    phi->addIncoming(call, callBB);
    phi->addIncoming(inlineResult, inlineBB);
  }

  // Really do the real inlining
  InlineFunctionInfo IFI(0, 0);
  if (CallInst *c = dyn_cast<CallInst>(inlineCall)) {
    c->setCalledFunction(function);
    InlineFunction(c, IFI);
  } else if (InvokeInst *c = dyn_cast<InvokeInst>(inlineCall)) {
    c->setCalledFunction(function);
    InlineFunction(c, IFI);
  }
}

// Cleanly removes a terminator instruction.
void GNUstep::removeTerminator(BasicBlock *BB) {
  TerminatorInst *BBTerm = BB->getTerminator();

  // Remove the BB as a predecessor from all of  successors
  for (unsigned i = 0, e = BBTerm->getNumSuccessors(); i != e; ++i) {
    BBTerm->getSuccessor(i)->removePredecessor(BB);
  }

  BBTerm->replaceAllUsesWith(UndefValue::get(BBTerm->getType()));
  // Remove the terminator instruction itself.
  BBTerm->eraseFromParent();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 "functions/sequences.h"
#include "functions/sequences_impl.h"

#include "runtime/sequences/sequences.h"
#include "runtime/sequences/SequencesImpl.h"
#include "system/globalenv.h"

#include "compiler/expression/expr.h"

#include "compiler/semantic_annotations/annotation_keys.h"
#include "compiler/semantic_annotations/tsv_annotation.h"

#include "types/typeops.h"

namespace zorba {

xqtref_t
op_concatenate::return_type(const std::vector<xqtref_t>& arg_types) const
{
  int sz = arg_types.size ();
  if (sz == 0)
    return GENV_TYPESYSTEM.EMPTY_TYPE;
  else {
    xqtref_t t = arg_types [0];
    TypeConstants::quantifier_t q = TypeConstants::QUANT_STAR;
    for (int i = 1; i < sz; i++) {
      t = TypeOps::union_type (*t, *arg_types [i]);
      TypeConstants::quantifier_t pq = TypeOps::quantifier (*t);
      if (pq == TypeConstants::QUANT_ONE || pq == TypeConstants::QUANT_PLUS)
        q = TypeConstants::QUANT_PLUS;
    }
    return GENV_TYPESYSTEM.create_type_x_quant (*t, q);
  }
}

void
op_concatenate::compute_annotation (
    AnnotationHolder *parent,
    std::vector<AnnotationHolder *> &kids,
    Annotations::Key k) const
{
  switch (k) {
    case Annotations::IGNORES_SORTED_NODES:
    case Annotations::IGNORES_DUP_NODES:
      for (std::vector<AnnotationHolder *>::iterator i = kids.begin (); i < kids.end (); i++)
        TSVAnnotationValue::update_annotation ((*i), k, parent->get_annotation (k));
      break;
    default: break;
  }
}

function* fn_sum::specialize(
   static_context* sctx,
   const std::vector<xqtref_t>& argTypes) const
{
  RootTypeManager& rtm = GENV_TYPESYSTEM;

  xqtref_t argType = argTypes[0];

  if (TypeOps::is_subtype(*argType, *rtm.UNTYPED_ATOMIC_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_double", get_arity());
  }
  else if (TypeOps::is_subtype(*argType, *rtm.DOUBLE_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_double", get_arity());
  }
  else if (TypeOps::is_subtype(*argType, *rtm.FLOAT_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_foat", get_arity());
  }
  else if (TypeOps::is_subtype(*argType, *rtm.INTEGER_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_integer", get_arity());
  }
  else if (TypeOps::is_subtype(*argType, *rtm.DECIMAL_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_decimal", get_arity());
  }
  else
  {
    return NULL;
  }
}

xqtref_t fn_exactly_one_noraise::return_type(
    const std::vector<xqtref_t>& arg_types) const
{
  if (theRaiseError)
    return TypeOps::prime_type(*arg_types[0]);
  else
    return function::return_type(arg_types);
}

PlanIter_t
fn_exactly_one_noraise::codegen(CompilerCB* aCb,
                                static_context* aSctx,
                                const QueryLoc& aLoc,
                                std::vector<PlanIter_t>& aArgs,
                                AnnotationHolder& aAnn) const
{
  return new FnExactlyOneIterator(aSctx,
                                  aLoc,
                                  aArgs,
                                  theRaiseError,
                                  testFlag(FunctionConsts::DoDistinct));
}

PlanIter_t
fn_union::codegen (
      CompilerCB* /*cb*/,
      static_context* sctx,
      const QueryLoc& loc,
      std::vector<PlanIter_t>& argv,
      AnnotationHolder &ann) const
{
  return new FnConcatIterator(sctx, loc, argv, false);
}

PlanIter_t fn_intersect::codegen(
    CompilerCB* /*cb*/,
    static_context* sctx,
    const QueryLoc& loc,
    std::vector<PlanIter_t>& argv,
    AnnotationHolder &ann) const
{
#if 0  // we can't access PRODUCES_* from the inputs, must rethink
  bool distinct = ann.get_annotation (Annotations::IGNORES_DUP_NODES) != TSVAnnotationValue::TRUE_VAL;
  bool sort = ann.get_annotation (Annotations::IGNORES_SORTED_NODES) != TSVAnnotationValue::TRUE_VAL;

  std::vector<PlanIter_t> inputs;
  for (std::vector<PlanIter_t>::iterator i = argv.begin ();
       i != argv.end (); i++)
    inputs.push_back (new NodeSortIterator (loc, *i, true, distinct, false));
  return new SortSemiJoinIterator(loc, inputs);
#endif

  return new HashSemiJoinIterator(sctx, loc, argv);
}

PlanIter_t
fn_except::codegen(
      CompilerCB* /*cb*/,
      static_context* sctx,
      const QueryLoc& loc,
      std::vector<PlanIter_t>& argv,
      AnnotationHolder& ann) const
{
  // TODO: use SortAntiJoinIterator when available (trac ticket 254)
  return new HashSemiJoinIterator(sctx, loc, argv, true);
}

void
fn_subsequence::compute_annotation(
    AnnotationHolder* parent,
    std::vector<AnnotationHolder *>& kids,
    Annotations::Key k) const
{
  switch (k) {
  case Annotations::IGNORES_SORTED_NODES:
  case Annotations::IGNORES_DUP_NODES:
    // don't use single_seq_fun default propagation rule
    return;
  default: single_seq_opt_function::compute_annotation (parent, kids, k);
  }
}

PlanIter_t
fn_subsequence::codegen(
      CompilerCB* /*cb*/,
      static_context* aSctx,
      const QueryLoc& aLoc,
      std::vector<PlanIter_t>& aArgs,
      AnnotationHolder& aAnn) const
{
  fo_expr& subseqExpr = static_cast<fo_expr&>(aAnn);

  const relpath_expr* pathExpr =
  dynamic_cast<const relpath_expr*>(subseqExpr[0].getp());

  const const_expr* posExpr =
  dynamic_cast<const const_expr*>(subseqExpr[1].getp());

  const const_expr* lenExpr = NULL;
  if (subseqExpr.size() > 2)
    lenExpr = dynamic_cast<const const_expr*>(subseqExpr[2].getp());

  if (posExpr != NULL && lenExpr != NULL && pathExpr != NULL)
  {
    xqp_double pos1 = posExpr->get_val()->getDoubleValue().round();
    long pos2 = static_cast<long>(pos1.getNumber());

    xqp_double len1 = lenExpr->get_val()->getDoubleValue().round();
    long len2 = static_cast<long>(pos1.getNumber());

    ulong numSteps = pathExpr->numSteps();

    if (pos2 > 0 && len2 == 1 && numSteps == 2)
    {
      AxisIteratorHelper* input = dynamic_cast<AxisIteratorHelper*>(aArgs[0].getp());
      assert(input != NULL);

      if (input->setTargetPos(pos2-1))
        return aArgs[0];
    }
  }

  return new FnSubsequenceIterator(aSctx, aLoc, aArgs);
}

xqtref_t
fn_zero_or_one::return_type(const std::vector<xqtref_t>& arg_types) const
{
  xqtref_t srcType = arg_types[0];

  return srcType->get_manager()->
         create_type(*TypeOps::prime_type(*srcType), TypeConstants::QUANT_QUESTION);
}

PlanIter_t
fn_zero_or_one::codegen(
      CompilerCB* /*cb*/,
      static_context* aSctx,
      const QueryLoc& aLoc,
      std::vector<PlanIter_t>& aArgs,
      AnnotationHolder& aAnn) const
{
  return new FnZeroOrOneIterator(aSctx,
                                 aLoc,
                                 aArgs,
                                 testFlag(FunctionConsts::DoDistinct));
}

PlanIter_t
fn_distinct_values::codegen(CompilerCB* /* cb */,
                   static_context* sctx,
                   const QueryLoc& loc,
                   std::vector<PlanIter_t>& argv,
                   AnnotationHolder &/*ann*/) const
{
  return new FnDistinctValuesIterator(sctx, loc, argv);
}

PlanIter_t
fn_max::codegen(
        CompilerCB* /*cb*/,
        static_context* aSctx,
        const QueryLoc& aLoc,
        std::vector<PlanIter_t>& aArgs,
        AnnotationHolder& /*aAnn*/) const
{
  return new FnMinMaxIterator(aSctx, aLoc, aArgs, FnMinMaxIterator::MAX);
}

PlanIter_t
fn_min::codegen(
        CompilerCB* /*cb*/,
        static_context* aSctx,
        const QueryLoc& aLoc,
        std::vector<PlanIter_t>& aArgs,
        AnnotationHolder& /*ann*/) const
{
  return new FnMinMaxIterator(aSctx, aLoc, aArgs, FnMinMaxIterator::MIN);
}

void
populate_context_sequences_impl(static_context* sctx)
{
  DECL(sctx, fn_exactly_one,
       (createQName(XQUERY_FN_NS,"fn","exactly-one"),
        GENV_TYPESYSTEM.ITEM_TYPE_STAR,
        GENV_TYPESYSTEM.ITEM_TYPE_ONE));

  DECL(sctx, fn_exactly_one_noraise,
       (createQName(XQUERY_FN_NS,"fn",":exactly-one-noraise"),
        GENV_TYPESYSTEM.ITEM_TYPE_STAR,
        GENV_TYPESYSTEM.BOOLEAN_TYPE_ONE));

  DECL(sctx, fn_union,
       (createQName(XQUERY_FN_NS,"fn",":union"),
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR, GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR));

  DECL(sctx, fn_intersect,
       (createQName(XQUERY_FN_NS,"fn",":intersect"),
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR, GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR));

  DECL(sctx, fn_except,
       (createQName(XQUERY_FN_NS,"fn",":except"),
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR, GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR));

  DECL(sctx, fn_distinct_values,
       (createQName(XQUERY_FN_NS,"fn","distinct-values"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR));

  DECL(sctx, fn_distinct_values,
       (createQName(XQUERY_FN_NS,"fn","distinct-values"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.STRING_TYPE_ONE,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR));
  DECL(sctx, fn_max,
       (createQName(XQUERY_FN_NS,"fn","max"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_QUESTION));

  DECL(sctx, fn_max,
       (createQName(XQUERY_FN_NS,"fn","max"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.STRING_TYPE_ONE,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_QUESTION));

  DECL(sctx, fn_min,
       (createQName(XQUERY_FN_NS,"fn","min"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_QUESTION));

  DECL(sctx, fn_min,
       (createQName(XQUERY_FN_NS,"fn","min"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.STRING_TYPE_ONE,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_QUESTION));

}

} /* namespace zorba */
<commit_msg>Added fn:id and fn:idref codegen.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 "functions/sequences.h"
#include "functions/sequences_impl.h"

#include "runtime/sequences/sequences.h"
#include "runtime/sequences/SequencesImpl.h"
#include "system/globalenv.h"

#include "compiler/expression/expr.h"

#include "compiler/semantic_annotations/annotation_keys.h"
#include "compiler/semantic_annotations/tsv_annotation.h"

#include "types/typeops.h"

namespace zorba {

xqtref_t
op_concatenate::return_type(const std::vector<xqtref_t>& arg_types) const
{
  int sz = arg_types.size ();
  if (sz == 0)
    return GENV_TYPESYSTEM.EMPTY_TYPE;
  else {
    xqtref_t t = arg_types [0];
    TypeConstants::quantifier_t q = TypeConstants::QUANT_STAR;
    for (int i = 1; i < sz; i++) {
      t = TypeOps::union_type (*t, *arg_types [i]);
      TypeConstants::quantifier_t pq = TypeOps::quantifier (*t);
      if (pq == TypeConstants::QUANT_ONE || pq == TypeConstants::QUANT_PLUS)
        q = TypeConstants::QUANT_PLUS;
    }
    return GENV_TYPESYSTEM.create_type_x_quant (*t, q);
  }
}

void
op_concatenate::compute_annotation (
    AnnotationHolder *parent,
    std::vector<AnnotationHolder *> &kids,
    Annotations::Key k) const
{
  switch (k) {
    case Annotations::IGNORES_SORTED_NODES:
    case Annotations::IGNORES_DUP_NODES:
      for (std::vector<AnnotationHolder *>::iterator i = kids.begin (); i < kids.end (); i++)
        TSVAnnotationValue::update_annotation ((*i), k, parent->get_annotation (k));
      break;
    default: break;
  }
}

function* fn_sum::specialize(
   static_context* sctx,
   const std::vector<xqtref_t>& argTypes) const
{
  RootTypeManager& rtm = GENV_TYPESYSTEM;

  xqtref_t argType = argTypes[0];

  if (TypeOps::is_subtype(*argType, *rtm.UNTYPED_ATOMIC_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_double", get_arity());
  }
  else if (TypeOps::is_subtype(*argType, *rtm.DOUBLE_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_double", get_arity());
  }
  else if (TypeOps::is_subtype(*argType, *rtm.FLOAT_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_foat", get_arity());
  }
  else if (TypeOps::is_subtype(*argType, *rtm.INTEGER_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_integer", get_arity());
  }
  else if (TypeOps::is_subtype(*argType, *rtm.DECIMAL_TYPE_STAR))
  {
    return sctx->lookup_builtin_fn("sum_decimal", get_arity());
  }
  else
  {
    return NULL;
  }
}

xqtref_t fn_exactly_one_noraise::return_type(
    const std::vector<xqtref_t>& arg_types) const
{
  if (theRaiseError)
    return TypeOps::prime_type(*arg_types[0]);
  else
    return function::return_type(arg_types);
}

PlanIter_t
fn_exactly_one_noraise::codegen(CompilerCB* aCb,
                                static_context* aSctx,
                                const QueryLoc& aLoc,
                                std::vector<PlanIter_t>& aArgs,
                                AnnotationHolder& aAnn) const
{
  return new FnExactlyOneIterator(aSctx,
                                  aLoc,
                                  aArgs,
                                  theRaiseError,
                                  testFlag(FunctionConsts::DoDistinct));
}

PlanIter_t
fn_union::codegen (
      CompilerCB* /*cb*/,
      static_context* sctx,
      const QueryLoc& loc,
      std::vector<PlanIter_t>& argv,
      AnnotationHolder &ann) const
{
  return new FnConcatIterator(sctx, loc, argv, false);
}

PlanIter_t fn_intersect::codegen(
    CompilerCB* /*cb*/,
    static_context* sctx,
    const QueryLoc& loc,
    std::vector<PlanIter_t>& argv,
    AnnotationHolder &ann) const
{
#if 0  // we can't access PRODUCES_* from the inputs, must rethink
  bool distinct = ann.get_annotation (Annotations::IGNORES_DUP_NODES) != TSVAnnotationValue::TRUE_VAL;
  bool sort = ann.get_annotation (Annotations::IGNORES_SORTED_NODES) != TSVAnnotationValue::TRUE_VAL;

  std::vector<PlanIter_t> inputs;
  for (std::vector<PlanIter_t>::iterator i = argv.begin ();
       i != argv.end (); i++)
    inputs.push_back (new NodeSortIterator (loc, *i, true, distinct, false));
  return new SortSemiJoinIterator(loc, inputs);
#endif

  return new HashSemiJoinIterator(sctx, loc, argv);
}

PlanIter_t
fn_except::codegen(
      CompilerCB* /*cb*/,
      static_context* sctx,
      const QueryLoc& loc,
      std::vector<PlanIter_t>& argv,
      AnnotationHolder& ann) const
{
  // TODO: use SortAntiJoinIterator when available (trac ticket 254)
  return new HashSemiJoinIterator(sctx, loc, argv, true);
}

void
fn_subsequence::compute_annotation(
    AnnotationHolder* parent,
    std::vector<AnnotationHolder *>& kids,
    Annotations::Key k) const
{
  switch (k) {
  case Annotations::IGNORES_SORTED_NODES:
  case Annotations::IGNORES_DUP_NODES:
    // don't use single_seq_fun default propagation rule
    return;
  default: single_seq_opt_function::compute_annotation (parent, kids, k);
  }
}

PlanIter_t
fn_subsequence::codegen(
      CompilerCB* /*cb*/,
      static_context* aSctx,
      const QueryLoc& aLoc,
      std::vector<PlanIter_t>& aArgs,
      AnnotationHolder& aAnn) const
{
  fo_expr& subseqExpr = static_cast<fo_expr&>(aAnn);

  const relpath_expr* pathExpr =
  dynamic_cast<const relpath_expr*>(subseqExpr[0].getp());

  const const_expr* posExpr =
  dynamic_cast<const const_expr*>(subseqExpr[1].getp());

  const const_expr* lenExpr = NULL;
  if (subseqExpr.size() > 2)
    lenExpr = dynamic_cast<const const_expr*>(subseqExpr[2].getp());

  if (posExpr != NULL && lenExpr != NULL && pathExpr != NULL)
  {
    xqp_double pos1 = posExpr->get_val()->getDoubleValue().round();
    long pos2 = static_cast<long>(pos1.getNumber());

    xqp_double len1 = lenExpr->get_val()->getDoubleValue().round();
    long len2 = static_cast<long>(pos1.getNumber());

    ulong numSteps = pathExpr->numSteps();

    if (pos2 > 0 && len2 == 1 && numSteps == 2)
    {
      AxisIteratorHelper* input = dynamic_cast<AxisIteratorHelper*>(aArgs[0].getp());
      assert(input != NULL);

      if (input->setTargetPos(pos2-1))
        return aArgs[0];
    }
  }

  return new FnSubsequenceIterator(aSctx, aLoc, aArgs);
}

xqtref_t
fn_zero_or_one::return_type(const std::vector<xqtref_t>& arg_types) const
{
  xqtref_t srcType = arg_types[0];

  return srcType->get_manager()->
         create_type(*TypeOps::prime_type(*srcType), TypeConstants::QUANT_QUESTION);
}

PlanIter_t
fn_zero_or_one::codegen(
      CompilerCB* /*cb*/,
      static_context* aSctx,
      const QueryLoc& aLoc,
      std::vector<PlanIter_t>& aArgs,
      AnnotationHolder& aAnn) const
{
  return new FnZeroOrOneIterator(aSctx,
                                 aLoc,
                                 aArgs,
                                 testFlag(FunctionConsts::DoDistinct));
}

PlanIter_t
fn_distinct_values::codegen(CompilerCB* /* cb */,
                   static_context* sctx,
                   const QueryLoc& loc,
                   std::vector<PlanIter_t>& argv,
                   AnnotationHolder &/*ann*/) const
{
  return new FnDistinctValuesIterator(sctx, loc, argv);
}

PlanIter_t
fn_max::codegen(
        CompilerCB* /*cb*/,
        static_context* aSctx,
        const QueryLoc& aLoc,
        std::vector<PlanIter_t>& aArgs,
        AnnotationHolder& /*aAnn*/) const
{
  return new FnMinMaxIterator(aSctx, aLoc, aArgs, FnMinMaxIterator::MAX);
}

PlanIter_t
fn_min::codegen(
        CompilerCB* /*cb*/,
        static_context* aSctx,
        const QueryLoc& aLoc,
        std::vector<PlanIter_t>& aArgs,
        AnnotationHolder& /*ann*/) const
{
  return new FnMinMaxIterator(aSctx, aLoc, aArgs, FnMinMaxIterator::MIN);
}

//15.5.2 fn:id
typedef function_impl<FnIdIterator> fn_id;

//15.5.3 fn:idref
typedef function_impl<FnIdRefIterator> fn_id_ref;

void
populate_context_sequences_impl(static_context* sctx)
{
  DECL(sctx, fn_exactly_one,
       (createQName(XQUERY_FN_NS,"fn","exactly-one"),
        GENV_TYPESYSTEM.ITEM_TYPE_STAR,
        GENV_TYPESYSTEM.ITEM_TYPE_ONE));

  DECL(sctx, fn_exactly_one_noraise,
       (createQName(XQUERY_FN_NS,"fn",":exactly-one-noraise"),
        GENV_TYPESYSTEM.ITEM_TYPE_STAR,
        GENV_TYPESYSTEM.BOOLEAN_TYPE_ONE));

  DECL(sctx, fn_union,
       (createQName(XQUERY_FN_NS,"fn",":union"),
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR, GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR));

  DECL(sctx, fn_intersect,
       (createQName(XQUERY_FN_NS,"fn",":intersect"),
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR, GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR));

  DECL(sctx, fn_except,
       (createQName(XQUERY_FN_NS,"fn",":except"),
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR, GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR));

  DECL(sctx, fn_distinct_values,
       (createQName(XQUERY_FN_NS,"fn","distinct-values"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR));

  DECL(sctx, fn_distinct_values,
       (createQName(XQUERY_FN_NS,"fn","distinct-values"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.STRING_TYPE_ONE,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR));
  DECL(sctx, fn_max,
       (createQName(XQUERY_FN_NS,"fn","max"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_QUESTION));

  DECL(sctx, fn_max,
       (createQName(XQUERY_FN_NS,"fn","max"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.STRING_TYPE_ONE,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_QUESTION));

  DECL(sctx, fn_min,
       (createQName(XQUERY_FN_NS,"fn","min"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_QUESTION));

  DECL(sctx, fn_min,
       (createQName(XQUERY_FN_NS,"fn","min"),
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_STAR,
        GENV_TYPESYSTEM.STRING_TYPE_ONE,
        GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_QUESTION));

  DECL(sctx, fn_id,
       (createQName(XQUERY_FN_NS,"fn","id"),
        GENV_TYPESYSTEM.STRING_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_ONE,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR)
      );

  DECL(sctx, fn_id_ref,
       (createQName(XQUERY_FN_NS,"fn","idref"),
        GENV_TYPESYSTEM.STRING_TYPE_STAR,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_ONE,
        GENV_TYPESYSTEM.ANY_NODE_TYPE_STAR));

}

} /* namespace zorba */
<|endoftext|>


<commit_before>/*     Copyright 2015-2018 Egor Yusov
*
*  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
*
*  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 OF ANY PROPRIETARY RIGHTS.
*
*  In no event and under no legal theory, whether in tort (including negligence),
*  contract, or otherwise, unless required by applicable law (such as deliberate
*  and grossly negligent acts) or agreed to in writing, shall any Contributor be
*  liable for any damages, including any direct, indirect, special, incidental,
*  or consequential damages of any character arising as a result of this License or
*  out of the use or inability to use the software (including but not limited to damages
*  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
*  all other commercial damages or losses), even if such Contributor has been advised
*  of the possibility of such damages.
*/

#include "AndroidFileSystem.h"
#include "EngineFactoryOpenGL.h"
#include "SampleApp.h"
#include "RenderDeviceGLES.h"
#include "AntTweakBar.h"

namespace Diligent
{

class SampleAppAndroid final : public SampleApp
{
public:
    SampleAppAndroid()
    {
        m_DeviceType = DeviceType::OpenGLES;
    }

    virtual void Initialize()override final
    {
        GetEngineFactoryOpenGL()->InitAndroidFileSystem(app_->activity, native_activity_class_name_.c_str());
        AndroidFileSystem::Init(app_->activity, native_activity_class_name_.c_str());
        SampleApp::Initialize();
        InitializeDiligentEngine(app_->window);
        m_RenderDeviceGLES = RefCntAutoPtr<IRenderDeviceGLES>(m_pDevice, IID_RenderDeviceGLES);
        m_TheSample->SetUIScale(3);
        InitializeSample();
    }

    virtual int Resume(ANativeWindow* window)override final
    {
        return m_RenderDeviceGLES->Resume(window);
    }

    virtual void TermDisplay()override final
    {
        // Tear down the EGL context currently associated with the display.
        m_RenderDeviceGLES->Suspend();
    }

    virtual void TrimMemory()override final
    {
        LOGI( "Trimming memory" );
        m_RenderDeviceGLES->Invalidate();
    }

    virtual int32_t HandleInput( AInputEvent* event )override final
    {
        if( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION )
        {
            ndk_helper::GESTURE_STATE doubleTapState = doubletap_detector_.Detect( event );
            ndk_helper::GESTURE_STATE dragState = drag_detector_.Detect( event );
            ndk_helper::GESTURE_STATE pinchState = pinch_detector_.Detect( event );

            //Double tap detector has a priority over other detectors
            if( doubleTapState == ndk_helper::GESTURE_STATE_ACTION )
            {
                //Detect double tap
                //tap_camera_.Reset( true );
            }
            else
            {
                //Handle drag state
                if( dragState & ndk_helper::GESTURE_STATE_START )
                {
                    //Otherwise, start dragging
                    ndk_helper::Vec2 v;
                    drag_detector_.GetPointer( v );
                    float fX = 0, fY = 0;
                    v.Value(fX, fY);
                    TwMouseMotion((short)fX, (short)fY);
                    int Handled = TwMouseButton( TW_MOUSE_PRESSED, TW_MOUSE_LEFT );
                    if (!Handled)
                    {
                        m_TheSample->GetInputController().BeginDrag(fX, fY);
                    }
                }
                else if( dragState & ndk_helper::GESTURE_STATE_MOVE )
                {
                    ndk_helper::Vec2 v;
                    drag_detector_.GetPointer( v );
                    float fX = 0, fY = 0;
                    v.Value(fX, fY);
                    int Handled = TwMouseMotion((short)fX, (short)fY);
                    m_TheSample->GetInputController().DragMove(fX, fY);
                }
                else if( dragState & ndk_helper::GESTURE_STATE_END )
                {
                    int Handled = TwMouseButton(TW_MOUSE_RELEASED, TW_MOUSE_LEFT);
                    m_TheSample->GetInputController().EndDrag();
                }

                //Handle pinch state
                if( pinchState & ndk_helper::GESTURE_STATE_START )
                {
                    //Start new pinch
                    ndk_helper::Vec2 v1;
                    ndk_helper::Vec2 v2;
                    pinch_detector_.GetPointers( v1, v2 );
                    float fX1 = 0, fY1 = 0, fX2 = 0, fY2 = 0;
                    v1.Value(fX1, fY1);
                    v2.Value(fX2, fY2);
                    m_TheSample->GetInputController().StartPinch(fX1, fY1, fX2, fY2);
                    //tap_camera_.BeginPinch( v1, v2 );
                }
                else if( pinchState & ndk_helper::GESTURE_STATE_MOVE )
                {
                    //Multi touch
                    //Start new pinch
                    ndk_helper::Vec2 v1;
                    ndk_helper::Vec2 v2;
                    pinch_detector_.GetPointers( v1, v2 );
                    float fX1 = 0, fY1 = 0, fX2 = 0, fY2 = 0;
                    v1.Value(fX1, fY1);
                    v2.Value(fX2, fY2);
                    m_TheSample->GetInputController().PinchMove(fX1, fY1, fX2, fY2);
                    //tap_camera_.Pinch( v1, v2 );
                }
                else if( pinchState & ndk_helper::GESTURE_STATE_END )
                {
                    m_TheSample->GetInputController().EndPinch();
                }
            }
            return 1;
        }
        return 0;
    }

private:
    RefCntAutoPtr<IRenderDeviceGLES> m_RenderDeviceGLES;
};

NativeAppBase* CreateApplication()
{
    return new SampleAppAndroid;
}

}

<commit_msg>Sample app android: enabled event handling by ImGui<commit_after>/*     Copyright 2015-2018 Egor Yusov
*
*  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
*
*  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 OF ANY PROPRIETARY RIGHTS.
*
*  In no event and under no legal theory, whether in tort (including negligence),
*  contract, or otherwise, unless required by applicable law (such as deliberate
*  and grossly negligent acts) or agreed to in writing, shall any Contributor be
*  liable for any damages, including any direct, indirect, special, incidental,
*  or consequential damages of any character arising as a result of this License or
*  out of the use or inability to use the software (including but not limited to damages
*  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
*  all other commercial damages or losses), even if such Contributor has been advised
*  of the possibility of such damages.
*/

#include "AndroidFileSystem.h"
#include "EngineFactoryOpenGL.h"
#include "SampleApp.h"
#include "RenderDeviceGLES.h"
#include "ImGuiImplAndroid.h"

namespace Diligent
{

class SampleAppAndroid final : public SampleApp
{
public:
    SampleAppAndroid()
    {
        m_DeviceType = DeviceType::OpenGLES;
    }

    virtual void Initialize()override final
    {
        GetEngineFactoryOpenGL()->InitAndroidFileSystem(app_->activity, native_activity_class_name_.c_str());
        AndroidFileSystem::Init(app_->activity, native_activity_class_name_.c_str());
        SampleApp::Initialize();
        InitializeDiligentEngine(app_->window);
        const auto& SCDesc = m_pSwapChain->GetDesc();
        m_pImGui.reset(new ImGuiImplAndroid(m_pDevice, SCDesc.ColorBufferFormat, SCDesc.DepthBufferFormat, SCDesc.Width, SCDesc.Height));
        m_RenderDeviceGLES = RefCntAutoPtr<IRenderDeviceGLES>(m_pDevice, IID_RenderDeviceGLES);
        InitializeSample();
    }

    virtual int Resume(ANativeWindow* window)override final
    {
        return m_RenderDeviceGLES->Resume(window);
    }

    virtual void TermDisplay()override final
    {
        // Tear down the EGL context currently associated with the display.
        m_RenderDeviceGLES->Suspend();
    }

    virtual void TrimMemory()override final
    {
        LOGI( "Trimming memory" );
        m_RenderDeviceGLES->Invalidate();
    }

    virtual int32_t HandleInput( AInputEvent* event )override final
    {
        if( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION )
        {
            ndk_helper::GESTURE_STATE doubleTapState = doubletap_detector_.Detect( event );
            ndk_helper::GESTURE_STATE dragState = drag_detector_.Detect( event );
            ndk_helper::GESTURE_STATE pinchState = pinch_detector_.Detect( event );

            //Double tap detector has a priority over other detectors
            if( doubleTapState == ndk_helper::GESTURE_STATE_ACTION )
            {
                //Detect double tap
                //tap_camera_.Reset( true );
            }
            else
            {
                //Handle drag state
                if( dragState & ndk_helper::GESTURE_STATE_START )
                {
                    //Otherwise, start dragging
                    ndk_helper::Vec2 v;
                    drag_detector_.GetPointer( v );
                    float fX = 0, fY = 0;
                    v.Value(fX, fY);
                    auto Handled = static_cast<ImGuiImplAndroid*>(m_pImGui.get())->BeginDrag(fX, fY);
                    if (!Handled)
                    {
                        m_TheSample->GetInputController().BeginDrag(fX, fY);
                    }
                }
                else if( dragState & ndk_helper::GESTURE_STATE_MOVE )
                {
                    ndk_helper::Vec2 v;
                    drag_detector_.GetPointer( v );
                    float fX = 0, fY = 0;
                    v.Value(fX, fY);
                    auto Handled = static_cast<ImGuiImplAndroid*>(m_pImGui.get())->DragMove(fX, fY);
                    if (!Handled)
                    {
                        m_TheSample->GetInputController().DragMove(fX, fY);
                    }
                }
                else if( dragState & ndk_helper::GESTURE_STATE_END )
                {
                    static_cast<ImGuiImplAndroid*>(m_pImGui.get())->EndDrag();
                    m_TheSample->GetInputController().EndDrag();
                }

                //Handle pinch state
                if( pinchState & ndk_helper::GESTURE_STATE_START )
                {
                    //Start new pinch
                    ndk_helper::Vec2 v1;
                    ndk_helper::Vec2 v2;
                    pinch_detector_.GetPointers( v1, v2 );
                    float fX1 = 0, fY1 = 0, fX2 = 0, fY2 = 0;
                    v1.Value(fX1, fY1);
                    v2.Value(fX2, fY2);
                    m_TheSample->GetInputController().StartPinch(fX1, fY1, fX2, fY2);
                    //tap_camera_.BeginPinch( v1, v2 );
                }
                else if( pinchState & ndk_helper::GESTURE_STATE_MOVE )
                {
                    //Multi touch
                    //Start new pinch
                    ndk_helper::Vec2 v1;
                    ndk_helper::Vec2 v2;
                    pinch_detector_.GetPointers( v1, v2 );
                    float fX1 = 0, fY1 = 0, fX2 = 0, fY2 = 0;
                    v1.Value(fX1, fY1);
                    v2.Value(fX2, fY2);
                    m_TheSample->GetInputController().PinchMove(fX1, fY1, fX2, fY2);
                    //tap_camera_.Pinch( v1, v2 );
                }
                else if( pinchState & ndk_helper::GESTURE_STATE_END )
                {
                    m_TheSample->GetInputController().EndPinch();
                }
            }
            return 1;
        }
        return 0;
    }

private:
    RefCntAutoPtr<IRenderDeviceGLES> m_RenderDeviceGLES;
};

NativeAppBase* CreateApplication()
{
    return new SampleAppAndroid;
}

}

<|endoftext|>


<commit_before>//===- DriverUtils.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains utility functions for the driver. Because there
// are so many small functions, we created this separate file to make
// Driver.cpp less cluttered.
//
//===----------------------------------------------------------------------===//

#include "Driver.h"
#include "Error.h"
#include "Memory.h"
#include "lld/Config/Version.h"
#include "lld/Core/Reproduce.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"

using namespace llvm;
using namespace llvm::sys;

using namespace lld;
using namespace lld::elf;

// Create OptTable

// Create prefix string literals used in Options.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Options.inc"
#undef PREFIX

// Create table mapping all options defined in Options.td
static const opt::OptTable::Info OptInfo[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10)            \
  {X1, X2, X9,          X10,         OPT_##ID, opt::Option::KIND##Class,       \
   X8, X7, OPT_##GROUP, OPT_##ALIAS, X6},
#include "Options.inc"
#undef OPTION
};

ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}

// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics.
static bool getColorDiagnostics(opt::InputArgList &Args) {
  bool Default = (ErrorOS == &errs() && Process::StandardErrHasColors());

  auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
                              OPT_no_color_diagnostics);
  if (!Arg)
    return Default;
  if (Arg->getOption().getID() == OPT_color_diagnostics)
    return true;
  if (Arg->getOption().getID() == OPT_no_color_diagnostics)
    return false;

  StringRef S = Arg->getValue();
  if (S == "auto")
    return Default;
  if (S == "always")
    return true;
  if (S != "never")
    error("unknown option: -color-diagnostics=" + S);
  return false;
}

static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
  if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
    StringRef S = Arg->getValue();
    if (S != "windows" && S != "posix")
      error("invalid response file quoting: " + S);
    if (S == "windows")
      return cl::TokenizeWindowsCommandLine;
    return cl::TokenizeGNUCommandLine;
  }
  if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
    return cl::TokenizeWindowsCommandLine;
  return cl::TokenizeGNUCommandLine;
}

// Parses a given list of options.
opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
  // Make InputArgList from string vectors.
  unsigned MissingIndex;
  unsigned MissingCount;
  SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());

  // We need to get the quoting style for response files before parsing all
  // options so we parse here before and ignore all the options but
  // --rsp-quoting.
  opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);

  // Expand response files (arguments in the form of @<filename>)
  // and then parse the argument again.
  cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
  Args = this->ParseArgs(Vec, MissingIndex, MissingCount);

  // Interpret -color-diagnostics early so that error messages
  // for unknown flags are colored.
  Config->ColorDiagnostics = getColorDiagnostics(Args);
  if (MissingCount)
    error(Twine(Args.getArgString(MissingIndex)) + ": missing argument");

  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
    error("unknown argument: " + Arg->getSpelling());
  return Args;
}

void elf::printHelp(const char *Argv0) {
  ELFOptTable Table;
  Table.PrintHelp(outs(), Argv0, "lld", false);
  outs() << "\n";

  // Scripts generated by Libtool versions up to at least 2.4.6 (the most
  // recent version as of March 2017) expect /supported targets:.* elf/ in
  // a message for the -help option. If it doesn't match, the scripts
  // assume that the linker doesn't support very basic features such as
  // shared libraries. Therefore, we need to print out at least "elf".
  // Here, we print out all the targets that we support.
  outs() << Argv0 << ": supported targets: "
         << "elf32-i386 elf32-iamcu elf32-littlearm elf32-powerpc "
         << "elf32-tradbigmips elf32-tradlittlemips elf32-x86-64 "
         << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc "
         << "elf64-tradbigmips elf64-tradlittlemips elf64-x86-64\n";
}

// Reconstructs command line arguments so that so that you can re-run
// the same command with the same inputs. This is for --reproduce.
std::string elf::createResponseFile(const opt::InputArgList &Args) {
  SmallString<0> Data;
  raw_svector_ostream OS(Data);

  // Copy the command line to the output while rewriting paths.
  for (auto *Arg : Args) {
    switch (Arg->getOption().getID()) {
    case OPT_reproduce:
      break;
    case OPT_INPUT:
      OS << quote(rewritePath(Arg->getValue())) << "\n";
      break;
    case OPT_o:
      // If -o path contains directories, "lld @response.txt" will likely
      // fail because the archive we are creating doesn't contain empty
      // directories for the output path (-o doesn't create directories).
      // Strip directories to prevent the issue.
      OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
      break;
    case OPT_L:
    case OPT_dynamic_list:
    case OPT_rpath:
    case OPT_alias_script_T:
    case OPT_script:
    case OPT_version_script:
      OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue()))
         << "\n";
      break;
    default:
      OS << toString(Arg) << "\n";
    }
  }
  return Data.str();
}

// Find a file by concatenating given paths. If a resulting path
// starts with "=", the character is replaced with a --sysroot value.
static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
  SmallString<128> S;
  if (Path1.startswith("="))
    path::append(S, Config->Sysroot, Path1.substr(1), Path2);
  else
    path::append(S, Path1, Path2);

  if (fs::exists(S))
    return S.str().str();
  return None;
}

Optional<std::string> elf::findFromSearchPaths(StringRef Path) {
  for (StringRef Dir : Config->SearchPaths)
    if (Optional<std::string> S = findFile(Dir, Path))
      return S;
  return None;
}

// This is for -lfoo. We'll look for libfoo.so or libfoo.a from
// search paths.
Optional<std::string> elf::searchLibrary(StringRef Name) {
  if (Name.startswith(":"))
    return findFromSearchPaths(Name.substr(1));

  for (StringRef Dir : Config->SearchPaths) {
    if (!Config->Static)
      if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".so"))
        return S;
    if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
      return S;
  }
  return None;
}
<commit_msg>Refine comment.<commit_after>//===- DriverUtils.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains utility functions for the driver. Because there
// are so many small functions, we created this separate file to make
// Driver.cpp less cluttered.
//
//===----------------------------------------------------------------------===//

#include "Driver.h"
#include "Error.h"
#include "Memory.h"
#include "lld/Config/Version.h"
#include "lld/Core/Reproduce.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"

using namespace llvm;
using namespace llvm::sys;

using namespace lld;
using namespace lld::elf;

// Create OptTable

// Create prefix string literals used in Options.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Options.inc"
#undef PREFIX

// Create table mapping all options defined in Options.td
static const opt::OptTable::Info OptInfo[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10)            \
  {X1, X2, X9,          X10,         OPT_##ID, opt::Option::KIND##Class,       \
   X8, X7, OPT_##GROUP, OPT_##ALIAS, X6},
#include "Options.inc"
#undef OPTION
};

ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}

// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics.
static bool getColorDiagnostics(opt::InputArgList &Args) {
  bool Default = (ErrorOS == &errs() && Process::StandardErrHasColors());

  auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
                              OPT_no_color_diagnostics);
  if (!Arg)
    return Default;
  if (Arg->getOption().getID() == OPT_color_diagnostics)
    return true;
  if (Arg->getOption().getID() == OPT_no_color_diagnostics)
    return false;

  StringRef S = Arg->getValue();
  if (S == "auto")
    return Default;
  if (S == "always")
    return true;
  if (S != "never")
    error("unknown option: -color-diagnostics=" + S);
  return false;
}

static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) {
  if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) {
    StringRef S = Arg->getValue();
    if (S != "windows" && S != "posix")
      error("invalid response file quoting: " + S);
    if (S == "windows")
      return cl::TokenizeWindowsCommandLine;
    return cl::TokenizeGNUCommandLine;
  }
  if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32)
    return cl::TokenizeWindowsCommandLine;
  return cl::TokenizeGNUCommandLine;
}

// Parses a given list of options.
opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
  // Make InputArgList from string vectors.
  unsigned MissingIndex;
  unsigned MissingCount;
  SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());

  // We need to get the quoting style for response files before parsing all
  // options so we parse here before and ignore all the options but
  // --rsp-quoting.
  opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);

  // Expand response files (arguments in the form of @<filename>)
  // and then parse the argument again.
  cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec);
  Args = this->ParseArgs(Vec, MissingIndex, MissingCount);

  // Interpret -color-diagnostics early so that error messages
  // for unknown flags are colored.
  Config->ColorDiagnostics = getColorDiagnostics(Args);
  if (MissingCount)
    error(Twine(Args.getArgString(MissingIndex)) + ": missing argument");

  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
    error("unknown argument: " + Arg->getSpelling());
  return Args;
}

void elf::printHelp(const char *Argv0) {
  ELFOptTable Table;
  Table.PrintHelp(outs(), Argv0, "lld", false);
  outs() << "\n";

  // Scripts generated by Libtool versions up to at least 2.4.6 (the most
  // recent version as of March 2017) expect /: supported targets:.* elf/
  // in a message for the -help option. If it doesn't match, the scripts
  // assume that the linker doesn't support very basic features such as
  // shared libraries. Therefore, we need to print out at least "elf".
  // Here, we print out all the targets that we support.
  outs() << Argv0 << ": supported targets: "
         << "elf32-i386 elf32-iamcu elf32-littlearm elf32-powerpc "
         << "elf32-tradbigmips elf32-tradlittlemips elf32-x86-64 "
         << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc "
         << "elf64-tradbigmips elf64-tradlittlemips elf64-x86-64\n";
}

// Reconstructs command line arguments so that so that you can re-run
// the same command with the same inputs. This is for --reproduce.
std::string elf::createResponseFile(const opt::InputArgList &Args) {
  SmallString<0> Data;
  raw_svector_ostream OS(Data);

  // Copy the command line to the output while rewriting paths.
  for (auto *Arg : Args) {
    switch (Arg->getOption().getID()) {
    case OPT_reproduce:
      break;
    case OPT_INPUT:
      OS << quote(rewritePath(Arg->getValue())) << "\n";
      break;
    case OPT_o:
      // If -o path contains directories, "lld @response.txt" will likely
      // fail because the archive we are creating doesn't contain empty
      // directories for the output path (-o doesn't create directories).
      // Strip directories to prevent the issue.
      OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
      break;
    case OPT_L:
    case OPT_dynamic_list:
    case OPT_rpath:
    case OPT_alias_script_T:
    case OPT_script:
    case OPT_version_script:
      OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue()))
         << "\n";
      break;
    default:
      OS << toString(Arg) << "\n";
    }
  }
  return Data.str();
}

// Find a file by concatenating given paths. If a resulting path
// starts with "=", the character is replaced with a --sysroot value.
static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
  SmallString<128> S;
  if (Path1.startswith("="))
    path::append(S, Config->Sysroot, Path1.substr(1), Path2);
  else
    path::append(S, Path1, Path2);

  if (fs::exists(S))
    return S.str().str();
  return None;
}

Optional<std::string> elf::findFromSearchPaths(StringRef Path) {
  for (StringRef Dir : Config->SearchPaths)
    if (Optional<std::string> S = findFile(Dir, Path))
      return S;
  return None;
}

// This is for -lfoo. We'll look for libfoo.so or libfoo.a from
// search paths.
Optional<std::string> elf::searchLibrary(StringRef Name) {
  if (Name.startswith(":"))
    return findFromSearchPaths(Name.substr(1));

  for (StringRef Dir : Config->SearchPaths) {
    if (!Config->Static)
      if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".so"))
        return S;
    if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a"))
      return S;
  }
  return None;
}
<|endoftext|>


<commit_before>// Copyright (c) 2008-2010 Kent State University
// Copyright (c) 2011-2012 Texas S&M University
//
// This file is distributed under the MIT License. See the accompanying file
// LICENSE.txt or http://www.opensource.org/licenses/mit-license.php for terms
// and conditions.

#ifndef ORIGIN_ITERATOR_STRIDE_HPP
#define ORIGIN_ITERATOR_STRIDE_HPP

#include <origin/iterator/facade.hpp>

namespace origin
{
  template <typename I, typename S>
    class stride_iterator;

  // An alias for the facade used by the stride iterator.
  template <typename I, typename S>
    using Stride_iterator_facade = iterator_facade<stride_iterator<I, S>, I>;

  // Stride iterator
  //
  // The stride iterator adaptor wraps an underlying iterator in such a way
  // that advancing a single stride (or step) will cause the underlying iterator
  // to advance a specified number of steps.
  //
  // The step function for a stride iterator must return a value greater than 0.
  // S step of 0 will not result in bounded ranges. Also note that that
  // reversing a stride iterator can be achieved using a reverse iterator
  // adaptor.
  //
  // Note: The bidirectional iterator operations are unchecked, meaning it
  // is possible to access elements that are before the first element of
  // the initial iterator value. Ensuring that these operations are checked
  // would require the addition of an extra iterator (the first iterator) and
  // checking those operations.
  //
  // Invariants:
  //    this->step() > 0
  template<typename I, typename Step = constant_function<Difference_type<I>>>
    class stride_iterator : public Stride_iterator_facade<I, Step>
    {
      static_assert(Iterator<I>(), "");
      static_assert(Function<Step>(), "");
    public:
      using Base = Stride_iterator_facade<I, Step>;

      stride_iterator(I first, I last, Step step = {})
        : data{first, last, step}
      {
        assert(step() > 0);
      }

      stride_iterator(I last, Step step = {})
        : stride_iterator(last, last, step)
      { }

      // Returns the underlying iterator
      I base() const { return first(); }

      // Returns the advance action.
      Step step_func() const { return inc(); }

      // Returns the step or stride for the iterator.
      constexpr Difference_type<I> step() const { return inc()(); }

      // Readable
      Iterator_reference<I> operator*() const;
      using Base::operator[];

      // Incrementable
      stride_iterator& operator++();
      using Base::operator++;

      // Decrementable
      stride_iterator& operator--();
      using Base::operator--;

      // Advance
      stride_iterator& operator+=(Difference_type<I> n);
      stride_iterator& operator-=(Difference_type<I> n);

    private:
      I&       first()       { return std::get<0>(data); }
      const I& first() const { return std::get<0>(data); }

      I&       last()       { return std::get<1>(data); }
      const I& last() const { return std::get<1>(data); }

      const Step& inc() const { return std::get<2>(data); }

    private:
      std::tuple<I, I, Step> data;
    };

  template <typename I, typename S>
    inline Iterator_reference<I>
    stride_iterator<I, S>::operator*() const
    {
      assert(first() != last());
      return *first();
    }

  template <typename I, typename S>
    inline auto
    stride_iterator<I, S>::operator++() -> stride_iterator&
    {
      assert(first() != last());
      first() = bounded_next(first(), step(), last());
      return *this;
    }

  template <typename I, typename S>
    inline auto
    stride_iterator<I, S>::operator--() -> stride_iterator&
    {
      first() = prev(first(), step());
      return *this;
    }

  template <typename I, typename S>
    inline auto
    stride_iterator<I, S>::operator+=(Difference_type<I> n)
      -> stride_iterator&
    {
      assert(first() != last());
      first() = bounded_next(first(), step() * n, last());
      return *this;
    }

  template <typename I, typename S>
    inline auto
    stride_iterator<I, S>::operator-=(Difference_type<I> n)
      -> stride_iterator&
    {
      first() *= prev(first(), step * n);
      return *this;
    }

  // Equality_comparable
  //
  // Two stride iterators are equal if they refer to the same object and have
  // the same step function.
  template <typename I, typename S>
    inline bool
    operator==(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() == b.base();
    }

  template <typename I, typename S>
    inline bool
    operator!=(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return !(a == b);
    }

  // Totally_ordered
  //
  // The ordering of stride iterators is defined by the ordering of the
  // underlying iterator. The order is undefined if the iterators have different
  // step functions.
  template <typename I, typename S>
    inline bool
    operator<(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() < b.base();
    }

  template <typename I, typename S>
    inline bool
    operator>(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() > b.base();
    }

  template <typename I, typename S>
    inline bool
    operator<=(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() <= b.base();
    }

  template <typename I, typename S>
    inline bool
    operator>=(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() >= b.base();
    }

  // Difference
  //
  // The difference between two stride iterators is undefined if a and b have
  // different step functions.
  template <typename I, typename S>
    inline Difference_type<I>
    operator-(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return (a.base() - b.base()) / a.stride();
    }

  // Make stride iterator
  //
  // Construct a stride iterator with some predetermined stride or step. There
  // are four overloads of this function:
  //
  //    make_stride_iterator(first, last, n) ~> i
  //    make_stride_iterator(last, n) ~> i
  //    make_stride_iterator(first, last, step) ~> i
  //    make_stride_iterator(last, step) ~> i
  //
  // The first two overloads construct stride iterators using a constant step n
  // where n is the difference type of first and last. These are the most
  // commonly used overloads.
  //
  // The last two overloads construct stride iterators whose step function is
  // given explicitly. These can be used to construct iteratos functions with
  // dynamic strides or whose strides are constant expressions. For example:
  //
  //    auto i = make_stride_iterator(f, l, literal(2));
  //
  // This creates a stride iterator whose stride is the literal value 2 (i.e.,
  // a constant expression).

  template <typename I>
    inline auto make_stride_iterator(I first, I last, Difference_type<I> n)
      -> Requires<Iterator<I>(), stride_iterator<I>>
    {
      using F = constant_function<Difference_type<I>>;
      return {first, last, F{n}};
    }

  template <typename I>
    inline auto make_stride_iterator(I last, Difference_type<I> n)
      -> Requires<Iterator<I>(), stride_iterator<I>>
    {
      using F = constant_function<Difference_type<I>>;
      return {last, F{n}};
    }

  template <typename I, typename Step>
    inline auto make_stride_iterator(I first, I last, Step step)
      -> Requires<Iterator<I>() && Function<Step>(), stride_iterator<I, Step>>
    {
      return {first, last, step};
    }

  template <typename I, typename Step>
    inline auto make_stride_iterator(I last, Step step)
      -> Requires<Iterator<I>() && Function<Step>(), stride_iterator<I, Step>>
    {
      return {last, step};
    }

} // namespace origin

#endif
<commit_msg>Small doc fix.<commit_after>// Copyright (c) 2008-2010 Kent State University
// Copyright (c) 2011-2012 Texas S&M University
//
// This file is distributed under the MIT License. See the accompanying file
// LICENSE.txt or http://www.opensource.org/licenses/mit-license.php for terms
// and conditions.

#ifndef ORIGIN_ITERATOR_STRIDE_HPP
#define ORIGIN_ITERATOR_STRIDE_HPP

#include <origin/iterator/facade.hpp>

namespace origin
{
  template <typename I, typename S>
    class stride_iterator;

  // An alias for the facade used by the stride iterator.
  template <typename I, typename S>
    using Stride_iterator_facade = iterator_facade<stride_iterator<I, S>, I>;

  // Stride iterator
  //
  // The stride iterator adaptor wraps an underlying iterator in such a way
  // that advancing a single stride (or step) will cause the underlying iterator
  // to advance a specified number of steps.
  //
  // The step function for a stride iterator must return a value greater than 0.
  // S step of 0 will not result in bounded ranges. Also note that that
  // reversing a stride iterator can be achieved using a reverse iterator
  // adaptor.
  //
  // Note: The bidirectional iterator operations are unchecked, meaning it
  // is possible to access elements that are before the first element of
  // the initial iterator value. Ensuring that these operations are checked
  // would require the addition of an extra iterator (the first iterator) and
  // checking those operations.
  //
  // Invariants:
  //    this->step() > 0
  template<typename I, typename Step = constant_function<Difference_type<I>>>
    class stride_iterator : public Stride_iterator_facade<I, Step>
    {
      static_assert(Iterator<I>(), "");
      static_assert(Function<Step>(), "");
    public:
      using Base = Stride_iterator_facade<I, Step>;

      stride_iterator(I first, I last, Step step = {})
        : data{first, last, step}
      {
        assert(step() > 0);
      }

      stride_iterator(I last, Step step = {})
        : stride_iterator(last, last, step)
      { }

      // Returns the underlying iterator
      I base() const { return first(); }

      // Returns the advance action.
      Step step_func() const { return inc(); }

      // Returns the step or stride for the iterator.
      constexpr Difference_type<I> step() const { return inc()(); }

      // Readable
      Iterator_reference<I> operator*() const;
      using Base::operator[];

      // Incrementable
      stride_iterator& operator++();
      using Base::operator++;

      // Decrementable
      stride_iterator& operator--();
      using Base::operator--;

      // Advance
      stride_iterator& operator+=(Difference_type<I> n);
      stride_iterator& operator-=(Difference_type<I> n);

    private:
      I&       first()       { return std::get<0>(data); }
      const I& first() const { return std::get<0>(data); }

      I&       last()       { return std::get<1>(data); }
      const I& last() const { return std::get<1>(data); }

      const Step& inc() const { return std::get<2>(data); }

    private:
      std::tuple<I, I, Step> data;
    };

  template <typename I, typename S>
    inline Iterator_reference<I>
    stride_iterator<I, S>::operator*() const
    {
      assert(first() != last());
      return *first();
    }

  template <typename I, typename S>
    inline auto
    stride_iterator<I, S>::operator++() -> stride_iterator&
    {
      assert(first() != last());
      first() = bounded_next(first(), step(), last());
      return *this;
    }

  template <typename I, typename S>
    inline auto
    stride_iterator<I, S>::operator--() -> stride_iterator&
    {
      first() = prev(first(), step());
      return *this;
    }

  template <typename I, typename S>
    inline auto
    stride_iterator<I, S>::operator+=(Difference_type<I> n)
      -> stride_iterator&
    {
      assert(first() != last());
      first() = bounded_next(first(), step() * n, last());
      return *this;
    }

  template <typename I, typename S>
    inline auto
    stride_iterator<I, S>::operator-=(Difference_type<I> n)
      -> stride_iterator&
    {
      first() *= prev(first(), step * n);
      return *this;
    }

  // Equality_comparable
  //
  // Two stride iterators are equal if they refer to the same object and have
  // the same step function.
  template <typename I, typename S>
    inline bool
    operator==(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() == b.base();
    }

  template <typename I, typename S>
    inline bool
    operator!=(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return !(a == b);
    }

  // Totally_ordered
  //
  // The ordering of stride iterators is defined by the ordering of the
  // underlying iterator. The order is undefined if the iterators have different
  // step functions.
  template <typename I, typename S>
    inline bool
    operator<(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() < b.base();
    }

  template <typename I, typename S>
    inline bool
    operator>(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() > b.base();
    }

  template <typename I, typename S>
    inline bool
    operator<=(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() <= b.base();
    }

  template <typename I, typename S>
    inline bool
    operator>=(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return a.base() >= b.base();
    }

  // Difference
  //
  // The difference between two stride iterators is undefined if a and b have
  // different step functions.
  template <typename I, typename S>
    inline Difference_type<I>
    operator-(const stride_iterator<I, S>& a, const stride_iterator<I, S>& b)
    {
      return (a.base() - b.base()) / a.stride();
    }

  // Make stride iterator
  //
  // Construct a stride iterator with some predetermined stride or step. There
  // are four overloads of this function:
  //
  //    make_stride_iterator(first, last, n) ~> i
  //    make_stride_iterator(last, n) ~> i
  //    make_stride_iterator(first, last, step) ~> i
  //    make_stride_iterator(last, step) ~> i
  //
  // The first two overloads construct stride iterators using a constant step n
  // where n is the difference type of first and last. These are the most
  // commonly used overloads.
  //
  // The last two overloads construct stride iterators whose step function is
  // given explicitly. These can be used to construct iteratos functions with
  // dynamic strides or whose strides are constant expressions. For example:
  //
  //    auto i = make_stride_iterator(f, l, integral_constant<int, 2>{});
  //
  // This creates a stride iterator whose stride is the literal value 2 (i.e.,
  // a constant expression).

  template <typename I>
    inline auto make_stride_iterator(I first, I last, Difference_type<I> n)
      -> Requires<Iterator<I>(), stride_iterator<I>>
    {
      using F = constant_function<Difference_type<I>>;
      return {first, last, F{n}};
    }

  template <typename I>
    inline auto make_stride_iterator(I last, Difference_type<I> n)
      -> Requires<Iterator<I>(), stride_iterator<I>>
    {
      using F = constant_function<Difference_type<I>>;
      return {last, F{n}};
    }

  template <typename I, typename Step>
    inline auto make_stride_iterator(I first, I last, Step step)
      -> Requires<Iterator<I>() && Function<Step>(), stride_iterator<I, Step>>
    {
      return {first, last, step};
    }

  template <typename I, typename Step>
    inline auto make_stride_iterator(I last, Step step)
      -> Requires<Iterator<I>() && Function<Step>(), stride_iterator<I, Step>>
    {
      return {last, step};
    }

} // namespace origin

#endif
<|endoftext|>