<commit_before>//===-- X86FloatingPoint.cpp - FP_REG_KILL inserter -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the pass which inserts FP_REG_KILL instructions.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "x86-codegen"
#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/Instructions.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/CFG.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;

STATISTIC(NumFPKill, "Number of FP_REG_KILL instructions added");

namespace {
  struct FPRegKiller : public MachineFunctionPass {
    static char ID;
    FPRegKiller() : MachineFunctionPass(&ID) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addPreservedID(MachineLoopInfoID);
      AU.addPreservedID(MachineDominatorsID);
      MachineFunctionPass::getAnalysisUsage(AU);
    }

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual const char *getPassName() const {
      return "X86 FP_REG_KILL inserter";
    }
  };
  char FPRegKiller::ID = 0;
}

FunctionPass *llvm::createX87FPRegKillInserterPass() {
  return new FPRegKiller();
}

/// ContainsFPStackCode - Return true if the specific MBB has floating point
/// stack code, and thus needs an FP_REG_KILL.
static bool ContainsFPStackCode(MachineBasicBlock *MBB, unsigned SSELevel,
                                MachineRegisterInfo &MRI) {
  // Scan the block, looking for instructions that define fp stack vregs.
  for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end();
       I != E; ++I) {
    if (I->getNumOperands() == 0 || !I->getOperand(0).isReg())
      continue;

    for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op) {
      if (!I->getOperand(op).isReg() || !I->getOperand(op).isDef() ||
          !TargetRegisterInfo::isVirtualRegister(I->getOperand(op).getReg()))
        continue;

      const TargetRegisterClass *RegClass =
        MRI.getRegClass(I->getOperand(op).getReg());

      switch (RegClass->getID())
      case X86::RFP32RegClassID:
      case X86::RFP64RegClassID:
      case X86::RFP80RegClassID:
      return true;
    }
  }

  // Check PHI nodes in successor blocks.  These PHI's will be lowered to have
  // a copy of the input value in this block.  In SSE mode, we only care about
  // 80-bit values.

  // Final check, check LLVM BB's that are successors to the LLVM BB
  // corresponding to BB for FP PHI nodes.
  const BasicBlock *LLVMBB = MBB->getBasicBlock();
  for (succ_const_iterator SI = succ_begin(LLVMBB), E = succ_end(LLVMBB);
       SI != E; ++SI) {
    const PHINode *PN;
    for (BasicBlock::const_iterator II = SI->begin();
         (PN = dyn_cast<PHINode>(II)); ++II) {
      if (PN->getType()->isX86_FP80Ty() ||
          (SSELevel == 0 && PN->getType()->isFloatingPointTy()) ||
          (SSELevel < 2 && PN->getType()->isDoubleTy())) {
        return true;
      }
    }
  }

  return false;
}

bool FPRegKiller::runOnMachineFunction(MachineFunction &MF) {
  // If we are emitting FP stack code, scan the basic block to determine if this
  // block defines any FP values.  If so, put an FP_REG_KILL instruction before
  // the terminator of the block.

  // Note that FP stack instructions are used in all modes for long double,
  // so we always need to do this check.
  // Also note that it's possible for an FP stack register to be live across
  // an instruction that produces multiple basic blocks (SSE CMOV) so we
  // must check all the generated basic blocks.

  // Scan all of the machine instructions in these MBBs, checking for FP
  // stores.  (RFP32 and RFP64 will not exist in SSE mode, but RFP80 might.)

  // Fast-path: If nothing is using the x87 registers, we don't need to do
  // any scanning.
  MachineRegisterInfo &MRI = MF.getRegInfo();
  if (MRI.getRegClassVirtRegs(X86::RFP80RegisterClass).empty() &&
      MRI.getRegClassVirtRegs(X86::RFP64RegisterClass).empty() &&
      MRI.getRegClassVirtRegs(X86::RFP32RegisterClass).empty())
    return false;

  const X86Subtarget &Subtarget = MF.getTarget().getSubtarget<X86Subtarget>();
  unsigned SSELevel = 0;
  if (Subtarget.hasSSE2())
    SSELevel = 2;
  else if (Subtarget.hasSSE1())
    SSELevel = 1;

  bool Changed = false;
  MachineFunction::iterator MBBI = MF.begin();
  MachineFunction::iterator EndMBB = MF.end();
  for (; MBBI != EndMBB; ++MBBI) {
    MachineBasicBlock *MBB = MBBI;

    // If this block returns, ignore it.  We don't want to insert an FP_REG_KILL
    // before the return.
    if (!MBB->empty()) {
      MachineBasicBlock::iterator EndI = MBB->end();
      --EndI;
      if (EndI->getDesc().isReturn())
        continue;
    }

    // If we find any FP stack code, emit the FP_REG_KILL instruction.
    if (ContainsFPStackCode(MBB, SSELevel, MRI)) {
      BuildMI(*MBB, MBBI->getFirstTerminator(), DebugLoc(),
              MF.getTarget().getInstrInfo()->get(X86::FP_REG_KILL));
      ++NumFPKill;
      Changed = true;
    }
  }

  return Changed;
}
<commit_msg>Use less evil form of switch stmt.<commit_after>//===-- X86FloatingPoint.cpp - FP_REG_KILL inserter -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the pass which inserts FP_REG_KILL instructions.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "x86-codegen"
#include "X86.h"
#include "X86InstrInfo.h"
#include "X86Subtarget.h"
#include "llvm/Instructions.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/CFG.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;

STATISTIC(NumFPKill, "Number of FP_REG_KILL instructions added");

namespace {
  struct FPRegKiller : public MachineFunctionPass {
    static char ID;
    FPRegKiller() : MachineFunctionPass(&ID) {}

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addPreservedID(MachineLoopInfoID);
      AU.addPreservedID(MachineDominatorsID);
      MachineFunctionPass::getAnalysisUsage(AU);
    }

    virtual bool runOnMachineFunction(MachineFunction &MF);

    virtual const char *getPassName() const {
      return "X86 FP_REG_KILL inserter";
    }
  };
  char FPRegKiller::ID = 0;
}

FunctionPass *llvm::createX87FPRegKillInserterPass() {
  return new FPRegKiller();
}

/// ContainsFPStackCode - Return true if the specific MBB has floating point
/// stack code, and thus needs an FP_REG_KILL.
static bool ContainsFPStackCode(MachineBasicBlock *MBB, unsigned SSELevel,
                                MachineRegisterInfo &MRI) {
  // Scan the block, looking for instructions that define fp stack vregs.
  for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end();
       I != E; ++I) {
    if (I->getNumOperands() == 0 || !I->getOperand(0).isReg())
      continue;

    for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op) {
      if (!I->getOperand(op).isReg() || !I->getOperand(op).isDef() ||
          !TargetRegisterInfo::isVirtualRegister(I->getOperand(op).getReg()))
        continue;

      const TargetRegisterClass *RegClass =
        MRI.getRegClass(I->getOperand(op).getReg());

      switch (RegClass->getID()) {
      default: break;
      case X86::RFP32RegClassID:
      case X86::RFP64RegClassID:
      case X86::RFP80RegClassID:
        return true;
      }
    }
  }

  // Check PHI nodes in successor blocks.  These PHI's will be lowered to have
  // a copy of the input value in this block.  In SSE mode, we only care about
  // 80-bit values.

  // Final check, check LLVM BB's that are successors to the LLVM BB
  // corresponding to BB for FP PHI nodes.
  const BasicBlock *LLVMBB = MBB->getBasicBlock();
  for (succ_const_iterator SI = succ_begin(LLVMBB), E = succ_end(LLVMBB);
       SI != E; ++SI) {
    const PHINode *PN;
    for (BasicBlock::const_iterator II = SI->begin();
         (PN = dyn_cast<PHINode>(II)); ++II) {
      if (PN->getType()->isX86_FP80Ty() ||
          (SSELevel == 0 && PN->getType()->isFloatingPointTy()) ||
          (SSELevel < 2 && PN->getType()->isDoubleTy())) {
        return true;
      }
    }
  }

  return false;
}

bool FPRegKiller::runOnMachineFunction(MachineFunction &MF) {
  // If we are emitting FP stack code, scan the basic block to determine if this
  // block defines any FP values.  If so, put an FP_REG_KILL instruction before
  // the terminator of the block.

  // Note that FP stack instructions are used in all modes for long double,
  // so we always need to do this check.
  // Also note that it's possible for an FP stack register to be live across
  // an instruction that produces multiple basic blocks (SSE CMOV) so we
  // must check all the generated basic blocks.

  // Scan all of the machine instructions in these MBBs, checking for FP
  // stores.  (RFP32 and RFP64 will not exist in SSE mode, but RFP80 might.)

  // Fast-path: If nothing is using the x87 registers, we don't need to do
  // any scanning.
  MachineRegisterInfo &MRI = MF.getRegInfo();
  if (MRI.getRegClassVirtRegs(X86::RFP80RegisterClass).empty() &&
      MRI.getRegClassVirtRegs(X86::RFP64RegisterClass).empty() &&
      MRI.getRegClassVirtRegs(X86::RFP32RegisterClass).empty())
    return false;

  const X86Subtarget &Subtarget = MF.getTarget().getSubtarget<X86Subtarget>();
  unsigned SSELevel = 0;
  if (Subtarget.hasSSE2())
    SSELevel = 2;
  else if (Subtarget.hasSSE1())
    SSELevel = 1;

  bool Changed = false;
  MachineFunction::iterator MBBI = MF.begin();
  MachineFunction::iterator EndMBB = MF.end();
  for (; MBBI != EndMBB; ++MBBI) {
    MachineBasicBlock *MBB = MBBI;

    // If this block returns, ignore it.  We don't want to insert an FP_REG_KILL
    // before the return.
    if (!MBB->empty()) {
      MachineBasicBlock::iterator EndI = MBB->end();
      --EndI;
      if (EndI->getDesc().isReturn())
        continue;
    }

    // If we find any FP stack code, emit the FP_REG_KILL instruction.
    if (ContainsFPStackCode(MBB, SSELevel, MRI)) {
      BuildMI(*MBB, MBBI->getFirstTerminator(), DebugLoc(),
              MF.getTarget().getInstrInfo()->get(X86::FP_REG_KILL));
      ++NumFPKill;
      Changed = true;
    }
  }

  return Changed;
}
<|endoftext|>


<commit_before>/* -----------------------------------------------------------------------------
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
----------------------------------------------------------------------------- */

// Author: Kevin P. Barry [ta0kira@gmail.com] [kevinbarry@google.com]

#include <condition_variable>
#include <functional>
#include <list>
#include <mutex>
#include <string>
#include <thread>
#include <queue>

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "thread-capture.h"
#include "thread-crosser.h"

using testing::ElementsAre;

namespace capture_thread {

class LogText : public ThreadCapture<LogText> {
 public:
  LogText() : cross_and_capture_to_(this) {}

  static void Log(std::string line) {
    if (GetCurrent()) {
      GetCurrent()->LogLine(std::move(line));
    }
  }

  const std::list<std::string> GetLinesUnsafe() {
    return lines_;
  }

 private:
  void LogLine(std::string line) {
    std::lock_guard<std::mutex> lock(data_lock_);
    lines_.emplace_back(std::move(line));
  }

  std::mutex data_lock_;
  std::list<std::string> lines_;
  const AutoThreadCrosser<LogText> cross_and_capture_to_;
};

class LogValues : public ThreadCapture<LogValues> {
 public:
  LogValues() : cross_and_capture_to_(this) {}

  static void Count(int count) {
    if (GetCurrent()) {
      GetCurrent()->LogCount(count);
    }
  }

  const std::list<int> GetCountsUnsafe() {
    return counts_;
  }

 private:
  void LogCount(int count) {
    std::lock_guard<std::mutex> lock(data_lock_);
    counts_.emplace_back(count);
  }

  std::mutex data_lock_;
  std::list<int> counts_;
  const AutoThreadCrosser<LogValues> cross_and_capture_to_;
};

class BlockingCallbackQueue {
 public:
  void Push(std::function<void()> callback) {
    std::lock_guard<std::mutex> lock(queue_lock_);
    queue_.push(std::move(callback));
    condition_.notify_all();
  }

  // NOTE: Calling before returning avoids a race condition if WaitUntilEmpty()
  // is used to wait until all calls complete.
  bool PopAndCall() {
    std::unique_lock<std::mutex> lock(queue_lock_);
    while (queue_.empty()) {
      condition_.wait(lock);
    }
    const bool valid = queue_.front().operator bool();
    if (valid) {
      queue_.front()();
    }
    queue_.pop();
    condition_.notify_all();
    return valid;
  }

  void WaitUntilEmpty() {
    std::unique_lock<std::mutex> lock(queue_lock_);
    while (!queue_.empty()) {
      condition_.wait(lock);
    }
  }

 private:
  std::mutex queue_lock_;
  std::condition_variable condition_;
  std::queue<std::function<void()>> queue_;
};

TEST(ThreadCaptureTest, NoLoggerInterferenceWithDifferentTypes) {
  LogText::Log("not logged");
  LogValues::Count(0);
  {
    LogText text_logger;
    LogText::Log("logged 1");
    {
      LogValues count_logger;
      LogValues::Count(1);
      LogText::Log("logged 2");
      EXPECT_THAT(count_logger.GetCountsUnsafe(), ElementsAre(1));
    }
    LogText::Log("logged 3");
    EXPECT_THAT(text_logger.GetLinesUnsafe(),
                ElementsAre("logged 1", "logged 2", "logged 3"));
  }
}

TEST(ThreadCaptureTest, SameTypeOverrides) {
    LogText text_logger1;
    LogText::Log("logged 1");
    {
      LogText text_logger2;
      LogText::Log("logged 2");
      EXPECT_THAT(text_logger2.GetLinesUnsafe(), ElementsAre("logged 2"));
    }
    LogText::Log("logged 3");
    EXPECT_THAT(text_logger1.GetLinesUnsafe(),
                ElementsAre("logged 1", "logged 3"));
}

TEST(ThreadCaptureTest, ThreadsAreNotCrossed) {
  LogText logger;
  LogText::Log("logged 1");

  std::thread worker([] {
        LogText::Log("logged 2");
      });
  worker.join();

  EXPECT_THAT(logger.GetLinesUnsafe(), ElementsAre("logged 1"));
}

TEST(ThreadCrosserTest, WrapCallIsFineWithoutLogger) {
  bool called = false;
  ThreadCrosser::WrapCall([&called] {
      called = true;
      LogText::Log("not logged");
    })();
  EXPECT_TRUE(called);
}

TEST(ThreadCrosserTest, WrapCallIsNotLazy) {
  LogText logger1;
  bool called = false;
  const auto callback = ThreadCrosser::WrapCall([&called] {
      called = true;
      LogText::Log("logged 1");
    });
  LogText logger2;
  callback();
  EXPECT_TRUE(called);
  EXPECT_THAT(logger1.GetLinesUnsafe(), ElementsAre("logged 1"));
  EXPECT_THAT(logger2.GetLinesUnsafe(), ElementsAre());
}

TEST(ThreadCrosserTest, WrapCallFallsThroughWithoutLogger) {
  bool called = false;
  const auto callback = ThreadCrosser::WrapCall([&called] {
      called = true;
      LogText::Log("logged 1");
    });
  LogText logger;
  callback();
  EXPECT_TRUE(called);
  EXPECT_THAT(logger.GetLinesUnsafe(), ElementsAre("logged 1"));
}

TEST(ThreadCrosserTest, WrapCallWithNullCallbackIsNull) {
  EXPECT_FALSE(ThreadCrosser::WrapCall(nullptr));
  LogText logger;
  EXPECT_FALSE(ThreadCrosser::WrapCall(nullptr));
}

TEST(ThreadCrosserTest, SingleThreadCrossing) {
  LogText logger;
  LogText::Log("logged 1");

  std::thread worker(ThreadCrosser::WrapCall([] {
        LogText::Log("logged 2");
      }));
  worker.join();

  EXPECT_THAT(logger.GetLinesUnsafe(), ElementsAre("logged 1", "logged 2"));
}

TEST(ThreadCrosserTest, MultipleThreadCrossingWithMultipleLoggers) {
  LogText text_logger;
  LogText::Log("logged 1");
  LogValues count_logger;
  LogValues::Count(1);

  std::thread worker(ThreadCrosser::WrapCall([] {
        std::thread worker(ThreadCrosser::WrapCall([] {
              LogText::Log("logged 2");
              LogValues::Count(2);
            }));
        worker.join();
      }));
  worker.join();

  EXPECT_THAT(text_logger.GetLinesUnsafe(),
              ElementsAre("logged 1", "logged 2"));
  EXPECT_THAT(count_logger.GetCountsUnsafe(), ElementsAre(1, 2));
}

TEST(ThreadCrosserTest, MultipleThreadCrossingWithDifferentLoggerScopes) {
  LogText text_logger;

  std::thread worker(ThreadCrosser::WrapCall([] {
        LogValues count_logger;
        std::thread worker(ThreadCrosser::WrapCall([] {
              LogText::Log("logged 1");
              LogValues::Count(1);
            }));
        worker.join();
        EXPECT_THAT(count_logger.GetCountsUnsafe(), ElementsAre(1));
      }));
  worker.join();

  EXPECT_THAT(text_logger.GetLinesUnsafe(), ElementsAre("logged 1"));
}

TEST(ThreadCrosserTest, DifferentLoggersInSameThread) {
  BlockingCallbackQueue queue;

  std::thread worker([&queue] {
        while (true) {
          LogText logger;
          if (!queue.PopAndCall()) {
            break;
          }
          LogText::Log("logged in thread");
          EXPECT_THAT(logger.GetLinesUnsafe(), ElementsAre("logged in thread"));
        }
      });

  LogText logger1;
  queue.Push(ThreadCrosser::WrapCall([] {
        LogText::Log("logged 1");
      }));
  queue.WaitUntilEmpty();
  EXPECT_THAT(logger1.GetLinesUnsafe(), ElementsAre("logged 1"));

  {
    // It's important for the test case that logger2 overrides logger1, i.e.,
    // that they are both in scope at the same time.
    LogText logger2;
    queue.Push(ThreadCrosser::WrapCall([] {
          LogText::Log("logged 2");
        }));
    queue.WaitUntilEmpty();
    EXPECT_THAT(logger2.GetLinesUnsafe(), ElementsAre("logged 2"));
  }

  queue.Push(ThreadCrosser::WrapCall([] {
        LogText::Log("logged 3");
      }));
  queue.WaitUntilEmpty();
  EXPECT_THAT(logger1.GetLinesUnsafe(), ElementsAre("logged 1", "logged 3"));

  queue.Push(nullptr);  // (Causes the thread to exit.)
  worker.join();
}

}  // namespace capture_thread

int main(int argc, char *argv[]) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Adds a ThreadCrosser unit test that changes stack order of loggers.<commit_after>/* -----------------------------------------------------------------------------
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
----------------------------------------------------------------------------- */

// Author: Kevin P. Barry [ta0kira@gmail.com] [kevinbarry@google.com]

#include <condition_variable>
#include <functional>
#include <list>
#include <mutex>
#include <string>
#include <thread>
#include <queue>

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "thread-capture.h"
#include "thread-crosser.h"

using testing::ElementsAre;

namespace capture_thread {

class LogText : public ThreadCapture<LogText> {
 public:
  LogText() : cross_and_capture_to_(this) {}

  static void Log(std::string line) {
    if (GetCurrent()) {
      GetCurrent()->LogLine(std::move(line));
    }
  }

  const std::list<std::string> GetLinesUnsafe() {
    return lines_;
  }

 private:
  void LogLine(std::string line) {
    std::lock_guard<std::mutex> lock(data_lock_);
    lines_.emplace_back(std::move(line));
  }

  std::mutex data_lock_;
  std::list<std::string> lines_;
  const AutoThreadCrosser<LogText> cross_and_capture_to_;
};

class LogValues : public ThreadCapture<LogValues> {
 public:
  LogValues() : cross_and_capture_to_(this) {}

  static void Count(int count) {
    if (GetCurrent()) {
      GetCurrent()->LogCount(count);
    }
  }

  const std::list<int> GetCountsUnsafe() {
    return counts_;
  }

 private:
  void LogCount(int count) {
    std::lock_guard<std::mutex> lock(data_lock_);
    counts_.emplace_back(count);
  }

  std::mutex data_lock_;
  std::list<int> counts_;
  const AutoThreadCrosser<LogValues> cross_and_capture_to_;
};

class BlockingCallbackQueue {
 public:
  void Push(std::function<void()> callback) {
    std::lock_guard<std::mutex> lock(queue_lock_);
    queue_.push(std::move(callback));
    condition_.notify_all();
  }

  // NOTE: Calling before returning avoids a race condition if WaitUntilEmpty()
  // is used to wait until all calls complete.
  bool PopAndCall() {
    std::unique_lock<std::mutex> lock(queue_lock_);
    while (queue_.empty()) {
      condition_.wait(lock);
    }
    const bool valid = queue_.front().operator bool();
    if (valid) {
      queue_.front()();
    }
    queue_.pop();
    condition_.notify_all();
    return valid;
  }

  void WaitUntilEmpty() {
    std::unique_lock<std::mutex> lock(queue_lock_);
    while (!queue_.empty()) {
      condition_.wait(lock);
    }
  }

 private:
  std::mutex queue_lock_;
  std::condition_variable condition_;
  std::queue<std::function<void()>> queue_;
};

TEST(ThreadCaptureTest, NoLoggerInterferenceWithDifferentTypes) {
  LogText::Log("not logged");
  LogValues::Count(0);
  {
    LogText text_logger;
    LogText::Log("logged 1");
    {
      LogValues count_logger;
      LogValues::Count(1);
      LogText::Log("logged 2");
      EXPECT_THAT(count_logger.GetCountsUnsafe(), ElementsAre(1));
    }
    LogText::Log("logged 3");
    EXPECT_THAT(text_logger.GetLinesUnsafe(),
                ElementsAre("logged 1", "logged 2", "logged 3"));
  }
}

TEST(ThreadCaptureTest, SameTypeOverrides) {
    LogText text_logger1;
    LogText::Log("logged 1");
    {
      LogText text_logger2;
      LogText::Log("logged 2");
      EXPECT_THAT(text_logger2.GetLinesUnsafe(), ElementsAre("logged 2"));
    }
    LogText::Log("logged 3");
    EXPECT_THAT(text_logger1.GetLinesUnsafe(),
                ElementsAre("logged 1", "logged 3"));
}

TEST(ThreadCaptureTest, ThreadsAreNotCrossed) {
  LogText logger;
  LogText::Log("logged 1");

  std::thread worker([] {
        LogText::Log("logged 2");
      });
  worker.join();

  EXPECT_THAT(logger.GetLinesUnsafe(), ElementsAre("logged 1"));
}

TEST(ThreadCrosserTest, WrapCallIsFineWithoutLogger) {
  bool called = false;
  ThreadCrosser::WrapCall([&called] {
      called = true;
      LogText::Log("not logged");
    })();
  EXPECT_TRUE(called);
}

TEST(ThreadCrosserTest, WrapCallIsNotLazy) {
  LogText logger1;
  bool called = false;
  const auto callback = ThreadCrosser::WrapCall([&called] {
      called = true;
      LogText::Log("logged 1");
    });
  LogText logger2;
  callback();
  EXPECT_TRUE(called);
  EXPECT_THAT(logger1.GetLinesUnsafe(), ElementsAre("logged 1"));
  EXPECT_THAT(logger2.GetLinesUnsafe(), ElementsAre());
}

TEST(ThreadCrosserTest, WrapCallFallsThroughWithoutLogger) {
  bool called = false;
  const auto callback = ThreadCrosser::WrapCall([&called] {
      called = true;
      LogText::Log("logged 1");
    });
  LogText logger;
  callback();
  EXPECT_TRUE(called);
  EXPECT_THAT(logger.GetLinesUnsafe(), ElementsAre("logged 1"));
}

TEST(ThreadCrosserTest, WrapCallWithNullCallbackIsNull) {
  EXPECT_FALSE(ThreadCrosser::WrapCall(nullptr));
  LogText logger;
  EXPECT_FALSE(ThreadCrosser::WrapCall(nullptr));
}

TEST(ThreadCrosserTest, SingleThreadCrossing) {
  LogText logger;
  LogText::Log("logged 1");

  std::thread worker(ThreadCrosser::WrapCall([] {
        LogText::Log("logged 2");
      }));
  worker.join();

  EXPECT_THAT(logger.GetLinesUnsafe(), ElementsAre("logged 1", "logged 2"));
}

TEST(ThreadCrosserTest, MultipleThreadCrossingWithMultipleLoggers) {
  LogText text_logger;
  LogText::Log("logged 1");
  LogValues count_logger;
  LogValues::Count(1);

  std::thread worker(ThreadCrosser::WrapCall([] {
        std::thread worker(ThreadCrosser::WrapCall([] {
              LogText::Log("logged 2");
              LogValues::Count(2);
            }));
        worker.join();
      }));
  worker.join();

  EXPECT_THAT(text_logger.GetLinesUnsafe(),
              ElementsAre("logged 1", "logged 2"));
  EXPECT_THAT(count_logger.GetCountsUnsafe(), ElementsAre(1, 2));
}

TEST(ThreadCrosserTest, MultipleThreadCrossingWithDifferentLoggerScopes) {
  LogText text_logger;

  std::thread worker(ThreadCrosser::WrapCall([] {
        LogValues count_logger;
        std::thread worker(ThreadCrosser::WrapCall([] {
              LogText::Log("logged 1");
              LogValues::Count(1);
            }));
        worker.join();
        EXPECT_THAT(count_logger.GetCountsUnsafe(), ElementsAre(1));
      }));
  worker.join();

  EXPECT_THAT(text_logger.GetLinesUnsafe(), ElementsAre("logged 1"));
}

TEST(ThreadCrosserTest, DifferentLoggersInSameThread) {
  BlockingCallbackQueue queue;

  std::thread worker([&queue] {
        while (true) {
          LogText logger;
          if (!queue.PopAndCall()) {
            break;
          }
          LogText::Log("logged in thread");
          EXPECT_THAT(logger.GetLinesUnsafe(), ElementsAre("logged in thread"));
        }
      });

  LogText logger1;
  queue.Push(ThreadCrosser::WrapCall([] {
        LogText::Log("logged 1");
      }));
  queue.WaitUntilEmpty();
  EXPECT_THAT(logger1.GetLinesUnsafe(), ElementsAre("logged 1"));

  {
    // It's important for the test case that logger2 overrides logger1, i.e.,
    // that they are both in scope at the same time.
    LogText logger2;
    queue.Push(ThreadCrosser::WrapCall([] {
          LogText::Log("logged 2");
        }));
    queue.WaitUntilEmpty();
    EXPECT_THAT(logger2.GetLinesUnsafe(), ElementsAre("logged 2"));
  }

  queue.Push(ThreadCrosser::WrapCall([] {
        LogText::Log("logged 3");
      }));
  queue.WaitUntilEmpty();
  EXPECT_THAT(logger1.GetLinesUnsafe(), ElementsAre("logged 1", "logged 3"));

  queue.Push(nullptr);  // (Causes the thread to exit.)
  worker.join();
}

TEST(ThreadCrosserTest, ReverseOrderOfLoggersOnStack) {
  LogText logger1;
  const auto callback = ThreadCrosser::WrapCall([] {
        LogText::Log("logged 1");
      });

  LogText logger2;
  const auto worker_call = ThreadCrosser::WrapCall([callback] {
        // In callback(), logger1 overrides logger2, whereas in the main thread
        // logger2 overrides logger1.
        callback();
        LogText::Log("logged 2");
      });

  LogText logger3;

  // Call using a thread.
  std::thread worker(worker_call);
  worker.join();

  EXPECT_THAT(logger1.GetLinesUnsafe(), ElementsAre("logged 1"));
  EXPECT_THAT(logger2.GetLinesUnsafe(), ElementsAre("logged 2"));
  EXPECT_THAT(logger3.GetLinesUnsafe(), ElementsAre());

  // Call in the main thread.
  worker_call();

  EXPECT_THAT(logger1.GetLinesUnsafe(), ElementsAre("logged 1", "logged 1"));
  EXPECT_THAT(logger2.GetLinesUnsafe(), ElementsAre("logged 2", "logged 2"));
  EXPECT_THAT(logger3.GetLinesUnsafe(), ElementsAre());
}

}  // namespace capture_thread

int main(int argc, char *argv[]) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>//===-- VPlanVerifier.cpp -------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the class VPlanVerifier, which contains utility functions
/// to check the consistency and invariants of a VPlan.
///
//===----------------------------------------------------------------------===//

#include "VPlanVerifier.h"
#include "llvm/ADT/DepthFirstIterator.h"

#define DEBUG_TYPE "loop-vectorize"

using namespace llvm;

static cl::opt<bool> EnableHCFGVerifier("vplan-verify-hcfg", cl::init(false),
                                        cl::Hidden,
                                        cl::desc("Verify VPlan H-CFG."));

/// Utility function that checks whether \p VPBlockVec has duplicate
/// VPBlockBases.
static bool hasDuplicates(const SmallVectorImpl<VPBlockBase *> &VPBlockVec) {
  SmallDenseSet<const VPBlockBase *, 8> VPBlockSet;
  for (const auto *Block : VPBlockVec) {
    if (VPBlockSet.count(Block))
      return true;
    VPBlockSet.insert(Block);
  }
  return false;
}

/// Helper function that verifies the CFG invariants of the VPBlockBases within
/// \p Region. Checks in this function are generic for VPBlockBases. They are
/// not specific for VPBasicBlocks or VPRegionBlocks.
static void verifyBlocksInRegion(const VPRegionBlock *Region) {
  for (const VPBlockBase *VPB :
       make_range(df_iterator<const VPBlockBase *>::begin(Region->getEntry()),
                  df_iterator<const VPBlockBase *>::end(Region->getExit()))) {
    // Check block's parent.
    assert(VPB->getParent() == Region && "VPBlockBase has wrong parent");

    // Check block's successors.
    const auto &Successors = VPB->getSuccessors();
    // There must be only one instance of a successor in block's successor list.
    // TODO: This won't work for switch statements.
    assert(!hasDuplicates(Successors) &&
           "Multiple instances of the same successor.");
    (void)hasDuplicates;

    for (const VPBlockBase *Succ : Successors) {
      // There must be a bi-directional link between block and successor.
      const auto &SuccPreds = Succ->getPredecessors();
      assert(std::find(SuccPreds.begin(), SuccPreds.end(), VPB) !=
                 SuccPreds.end() &&
             "Missing predecessor link.");
      (void)SuccPreds;
    }

    // Check block's predecessors.
    const auto &Predecessors = VPB->getPredecessors();
    // There must be only one instance of a predecessor in block's predecessor
    // list.
    // TODO: This won't work for switch statements.
    assert(!hasDuplicates(Predecessors) &&
           "Multiple instances of the same predecessor.");

    for (const VPBlockBase *Pred : Predecessors) {
      // Block and predecessor must be inside the same region.
      assert(Pred->getParent() == VPB->getParent() &&
             "Predecessor is not in the same region.");

      // There must be a bi-directional link between block and predecessor.
      const auto &PredSuccs = Pred->getSuccessors();
      assert(std::find(PredSuccs.begin(), PredSuccs.end(), VPB) !=
                 PredSuccs.end() &&
             "Missing successor link.");
      (void)PredSuccs;
    }
  }
}

/// Verify the CFG invariants of VPRegionBlock \p Region and its nested
/// VPBlockBases. Do not recurse inside nested VPRegionBlocks.
static void verifyRegion(const VPRegionBlock *Region) {
  const VPBlockBase *Entry = Region->getEntry();
  const VPBlockBase *Exit = Region->getExit();

  // Entry and Exit shouldn't have any predecessor/successor, respectively.
  assert(!Entry->getNumPredecessors() && "Region entry has predecessors.");
  assert(!Exit->getNumSuccessors() && "Region exit has successors.");
  (void)Entry;
  (void)Exit;

  verifyBlocksInRegion(Region);
}

/// Verify the CFG invariants of VPRegionBlock \p Region and its nested
/// VPBlockBases. Recurse inside nested VPRegionBlocks.
static void verifyRegionRec(const VPRegionBlock *Region) {
  verifyRegion(Region);

  // Recurse inside nested regions.
  for (const VPBlockBase *VPB :
       make_range(df_iterator<const VPBlockBase *>::begin(Region->getEntry()),
                  df_iterator<const VPBlockBase *>::end(Region->getExit()))) {
    if (const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB))
      verifyRegionRec(SubRegion);
  }
}

void VPlanVerifier::verifyHierarchicalCFG(
    const VPRegionBlock *TopRegion) const {
  if (!EnableHCFGVerifier)
    return;

  DEBUG(dbgs() << "Verifying VPlan H-CFG.\n");
  assert(!TopRegion->getParent() && "VPlan Top Region should have no parent.");
  verifyRegionRec(TopRegion);
}
<commit_msg>Fix warning from r332654 with LLVM_ATTRIBUTE_USED<commit_after>//===-- VPlanVerifier.cpp -------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the class VPlanVerifier, which contains utility functions
/// to check the consistency and invariants of a VPlan.
///
//===----------------------------------------------------------------------===//

#include "VPlanVerifier.h"
#include "llvm/ADT/DepthFirstIterator.h"

#define DEBUG_TYPE "loop-vectorize"

using namespace llvm;

static cl::opt<bool> EnableHCFGVerifier("vplan-verify-hcfg", cl::init(false),
                                        cl::Hidden,
                                        cl::desc("Verify VPlan H-CFG."));

/// Utility function that checks whether \p VPBlockVec has duplicate
/// VPBlockBases.
LLVM_ATTRIBUTE_USED static bool
hasDuplicates(const SmallVectorImpl<VPBlockBase *> &VPBlockVec) {
  SmallDenseSet<const VPBlockBase *, 8> VPBlockSet;
  for (const auto *Block : VPBlockVec) {
    if (VPBlockSet.count(Block))
      return true;
    VPBlockSet.insert(Block);
  }
  return false;
}

/// Helper function that verifies the CFG invariants of the VPBlockBases within
/// \p Region. Checks in this function are generic for VPBlockBases. They are
/// not specific for VPBasicBlocks or VPRegionBlocks.
static void verifyBlocksInRegion(const VPRegionBlock *Region) {
  for (const VPBlockBase *VPB :
       make_range(df_iterator<const VPBlockBase *>::begin(Region->getEntry()),
                  df_iterator<const VPBlockBase *>::end(Region->getExit()))) {
    // Check block's parent.
    assert(VPB->getParent() == Region && "VPBlockBase has wrong parent");

    // Check block's successors.
    const auto &Successors = VPB->getSuccessors();
    // There must be only one instance of a successor in block's successor list.
    // TODO: This won't work for switch statements.
    assert(!hasDuplicates(Successors) &&
           "Multiple instances of the same successor.");

    for (const VPBlockBase *Succ : Successors) {
      // There must be a bi-directional link between block and successor.
      const auto &SuccPreds = Succ->getPredecessors();
      assert(std::find(SuccPreds.begin(), SuccPreds.end(), VPB) !=
                 SuccPreds.end() &&
             "Missing predecessor link.");
      (void)SuccPreds;
    }

    // Check block's predecessors.
    const auto &Predecessors = VPB->getPredecessors();
    // There must be only one instance of a predecessor in block's predecessor
    // list.
    // TODO: This won't work for switch statements.
    assert(!hasDuplicates(Predecessors) &&
           "Multiple instances of the same predecessor.");

    for (const VPBlockBase *Pred : Predecessors) {
      // Block and predecessor must be inside the same region.
      assert(Pred->getParent() == VPB->getParent() &&
             "Predecessor is not in the same region.");

      // There must be a bi-directional link between block and predecessor.
      const auto &PredSuccs = Pred->getSuccessors();
      assert(std::find(PredSuccs.begin(), PredSuccs.end(), VPB) !=
                 PredSuccs.end() &&
             "Missing successor link.");
      (void)PredSuccs;
    }
  }
}

/// Verify the CFG invariants of VPRegionBlock \p Region and its nested
/// VPBlockBases. Do not recurse inside nested VPRegionBlocks.
static void verifyRegion(const VPRegionBlock *Region) {
  const VPBlockBase *Entry = Region->getEntry();
  const VPBlockBase *Exit = Region->getExit();

  // Entry and Exit shouldn't have any predecessor/successor, respectively.
  assert(!Entry->getNumPredecessors() && "Region entry has predecessors.");
  assert(!Exit->getNumSuccessors() && "Region exit has successors.");
  (void)Entry;
  (void)Exit;

  verifyBlocksInRegion(Region);
}

/// Verify the CFG invariants of VPRegionBlock \p Region and its nested
/// VPBlockBases. Recurse inside nested VPRegionBlocks.
static void verifyRegionRec(const VPRegionBlock *Region) {
  verifyRegion(Region);

  // Recurse inside nested regions.
  for (const VPBlockBase *VPB :
       make_range(df_iterator<const VPBlockBase *>::begin(Region->getEntry()),
                  df_iterator<const VPBlockBase *>::end(Region->getExit()))) {
    if (const auto *SubRegion = dyn_cast<VPRegionBlock>(VPB))
      verifyRegionRec(SubRegion);
  }
}

void VPlanVerifier::verifyHierarchicalCFG(
    const VPRegionBlock *TopRegion) const {
  if (!EnableHCFGVerifier)
    return;

  DEBUG(dbgs() << "Verifying VPlan H-CFG.\n");
  assert(!TopRegion->getParent() && "VPlan Top Region should have no parent.");
  verifyRegionRec(TopRegion);
}
<|endoftext|>


<commit_before>#pragma once

#include <array>
#include <vector>
#include <ostream>

#ifdef DEBUG
#	include <iostream>
#endif

#include "util.hpp"
#include "debug.hpp"

namespace utki{

// TODO: remove when C++'20 becomes very common.

/**
 * @brief span template class.
 * This class is a wrapper of continuous memory buffer, it encapsulates pointer to memory block and size of that memory block.
 * It does not own the memory.
 * This is a replacement of std::span when C++'20 is not available.
 */
template <class T> class span final{
public:
	typedef T value_type;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	typedef value_type* iterator;
	typedef const value_type* const_iterator;
	typedef std::size_t size_type;
	typedef std::ptrdiff_t difference_type;
	typedef std::reverse_iterator<iterator> reverse_iterator;
	typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

private:
	pointer buf = nullptr;
	size_type bufSize = 0;

public:

	span(const span&) = default;
	span& operator=(const span&) = default;

	/**
	 * @brief Create a span object.
	 * Creates a span object which wraps given memory buffer of specified size.
	 * Note, the memory will not be freed upon this Buffer object destruction,
	 * Buffer does not own the memory.
	 * @param bufPtr - pointer to the memory buffer.
	 * @param bufSize - size of the memory buffer.
	 */
	span(pointer bufPtr, size_type bufSize)noexcept :
			buf(bufPtr),
			bufSize(bufSize)
	{}

	span()noexcept{}

	/**
	 * @brief Constructor for automatic conversion from nullptr.
     * @param bufPtr - pointer to the memory buffer. Makes not much sense, because size is 0 anyway.
     */
	span(nullptr_t)noexcept :
			buf(nullptr),
			bufSize(0)
	{}

	/**
	 * @brief get buffer size.
	 * @return number of elements in buffer.
	 */
	size_type size()const noexcept{
		return this->bufSize;
	}

	bool empty()const noexcept{
		return this->size() == 0;
	}

	/**
	 * @brief get size of buffer in bytes.
	 * @return size of array in bytes.
	 */
	size_type size_bytes()const noexcept{
		return this->size() * sizeof(value_type);
	}

	//TODO: deprecated, remove.
	size_type sizeInBytes()const noexcept{
		return this->size_bytes();
	}

	/**
	 * @brief access specified element of the buffer.
	 * Const version of Buffer::operator[].
	 * @param i - element index.
	 * @return reference to i'th element of the buffer.
	 */
	const_reference operator[](size_type i)const noexcept{
		ASSERT(i < this->size())
		return this->buf[i];
	}

	/**
	 * @brief access specified element of the buffer.
	 * @param i - element index.
	 * @return reference to i'th element of the buffer.
	 */
	reference operator[](size_type i)noexcept{
		ASSERT_INFO(i < this->size(), "operator[]: index out of bounds")
		return this->buf[i];
	}

	/**
	 * @brief get pointer to first element of the buffer.
	 * @return pointer to first element of the buffer.
	 */
	iterator begin()noexcept{
		return this->buf;
	}

	/**
	 * @brief get pointer to first element of the buffer.
	 * @return pointer to first element of the buffer.
	 */
	const_iterator begin()const noexcept{
		return this->cbegin();
	}

	const_iterator cbegin()const noexcept{
		return this->buf;
	}

	/**
	 * @brief get pointer to "after last" element of the buffer.
	 * @return pointer to "after last" element of the buffer.
	 */
	iterator end()noexcept{
		return this->buf + this->bufSize;
	}

	/**
	 * @brief get const pointer to "after last" element of the buffer.
	 * @return const pointer to "after last" element of the buffer.
	 */
	const_iterator end()const noexcept{
		return this->cend();
	}

	const_iterator cend()const noexcept{
		return this->buf + this->bufSize;
	}

	const_reverse_iterator crbegin()const noexcept{
		return const_reverse_iterator(this->end());
	}

	const_reverse_iterator crend()const noexcept{
		return const_reverse_iterator(this->begin());
	}

	reverse_iterator rbegin()noexcept{
		return reverse_iterator(this->end());
	}

	const_reverse_iterator rbegin()const noexcept{
		return const_reverse_iterator(this->end());
	}

	reverse_iterator rend()noexcept{
		return reverse_iterator(this->begin());
	}

	const_reverse_iterator rend()const noexcept{
		return const_reverse_iterator(this->begin());
	}

	pointer data()noexcept{
		return this->buf;
	}

	const_pointer data()const noexcept{
		return this->buf;
	}

	/**
	 * @brief Checks if pointer points somewhere within the buffer.
	 * @param p - pointer to check.
	 * @return true - if pointer passed as argument points somewhere within the buffer.
	 * @return false otherwise.
	 */
	bool overlaps(const_pointer p)const noexcept{
		return this->begin() <= p && p <= (this->end() - 1);
	}

	friend std::ostream& operator<<(std::ostream& s, const span<T>& buf){
		for(auto& e : buf){
			s << e;
		}
		return s;
	}
};

template <class T> inline utki::span<T> make_span(nullptr_t){
	return utki::span<T>(nullptr);
}

template <class T> inline utki::span<T> make_span(T* buf, size_t size){
	return utki::span<T>(buf, size);
}

template <class T> inline const utki::span<T> make_span(const T* buf, size_t size){
	return utki::span<T>(const_cast<T*>(buf), size);
}

template <class T, std::size_t array_size> inline utki::span<T> make_span(std::array<T, array_size>& a){
	return make_span(a.size() == 0 ? nullptr : &*a.begin(), a.size());
}

template <class T, std::size_t array_size> inline const utki::span<T> make_span(const std::array<T, array_size>& a){
	return make_span(a.size() == 0 ? nullptr : &*a.begin(), a.size());
}

template <class T> inline utki::span<T> make_span(std::vector<T>& v){
	return make_span(v.size() == 0 ? nullptr : &*v.begin(), v.size());
}

template <class T> inline const utki::span<T> make_span(const std::vector<T>& v){
	return make_span(v.size() == 0 ? nullptr : &*v.begin(), v.size());
}

inline std::string to_string(const utki::span<char>& buf){
	return std::string(buf.data(), buf.size());
}

}
<commit_msg>build fix<commit_after>#pragma once

#include <array>
#include <vector>
#include <ostream>

#ifdef DEBUG
#	include <iostream>
#endif

#include "util.hpp"
#include "debug.hpp"

namespace utki{

// TODO: remove when C++'20 becomes very common.

/**
 * @brief span template class.
 * This class is a wrapper of continuous memory buffer, it encapsulates pointer to memory block and size of that memory block.
 * It does not own the memory.
 * This is a replacement of std::span when C++'20 is not available.
 */
template <class T> class span final{
public:
	typedef T value_type;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	typedef value_type* iterator;
	typedef const value_type* const_iterator;
	typedef std::size_t size_type;
	typedef std::ptrdiff_t difference_type;
	typedef std::reverse_iterator<iterator> reverse_iterator;
	typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

private:
	pointer buf = nullptr;
	size_type bufSize = 0;

public:

	span(const span&) = default;
	span& operator=(const span&) = default;

	/**
	 * @brief Create a span object.
	 * Creates a span object which wraps given memory buffer of specified size.
	 * Note, the memory will not be freed upon this Buffer object destruction,
	 * Buffer does not own the memory.
	 * @param bufPtr - pointer to the memory buffer.
	 * @param bufSize - size of the memory buffer.
	 */
	span(pointer bufPtr, size_type bufSize)noexcept :
			buf(bufPtr),
			bufSize(bufSize)
	{}

	span()noexcept{}

	/**
	 * @brief Constructor for automatic conversion from nullptr.
     * @param bufPtr - pointer to the memory buffer. Makes not much sense, because size is 0 anyway.
     */
	span(std::nullptr_t)noexcept :
			buf(nullptr),
			bufSize(0)
	{}

	/**
	 * @brief get buffer size.
	 * @return number of elements in buffer.
	 */
	size_type size()const noexcept{
		return this->bufSize;
	}

	bool empty()const noexcept{
		return this->size() == 0;
	}

	/**
	 * @brief get size of buffer in bytes.
	 * @return size of array in bytes.
	 */
	size_type size_bytes()const noexcept{
		return this->size() * sizeof(value_type);
	}

	//TODO: deprecated, remove.
	size_type sizeInBytes()const noexcept{
		return this->size_bytes();
	}

	/**
	 * @brief access specified element of the buffer.
	 * Const version of Buffer::operator[].
	 * @param i - element index.
	 * @return reference to i'th element of the buffer.
	 */
	const_reference operator[](size_type i)const noexcept{
		ASSERT(i < this->size())
		return this->buf[i];
	}

	/**
	 * @brief access specified element of the buffer.
	 * @param i - element index.
	 * @return reference to i'th element of the buffer.
	 */
	reference operator[](size_type i)noexcept{
		ASSERT_INFO(i < this->size(), "operator[]: index out of bounds")
		return this->buf[i];
	}

	/**
	 * @brief get pointer to first element of the buffer.
	 * @return pointer to first element of the buffer.
	 */
	iterator begin()noexcept{
		return this->buf;
	}

	/**
	 * @brief get pointer to first element of the buffer.
	 * @return pointer to first element of the buffer.
	 */
	const_iterator begin()const noexcept{
		return this->cbegin();
	}

	const_iterator cbegin()const noexcept{
		return this->buf;
	}

	/**
	 * @brief get pointer to "after last" element of the buffer.
	 * @return pointer to "after last" element of the buffer.
	 */
	iterator end()noexcept{
		return this->buf + this->bufSize;
	}

	/**
	 * @brief get const pointer to "after last" element of the buffer.
	 * @return const pointer to "after last" element of the buffer.
	 */
	const_iterator end()const noexcept{
		return this->cend();
	}

	const_iterator cend()const noexcept{
		return this->buf + this->bufSize;
	}

	const_reverse_iterator crbegin()const noexcept{
		return const_reverse_iterator(this->end());
	}

	const_reverse_iterator crend()const noexcept{
		return const_reverse_iterator(this->begin());
	}

	reverse_iterator rbegin()noexcept{
		return reverse_iterator(this->end());
	}

	const_reverse_iterator rbegin()const noexcept{
		return const_reverse_iterator(this->end());
	}

	reverse_iterator rend()noexcept{
		return reverse_iterator(this->begin());
	}

	const_reverse_iterator rend()const noexcept{
		return const_reverse_iterator(this->begin());
	}

	pointer data()noexcept{
		return this->buf;
	}

	const_pointer data()const noexcept{
		return this->buf;
	}

	/**
	 * @brief Checks if pointer points somewhere within the buffer.
	 * @param p - pointer to check.
	 * @return true - if pointer passed as argument points somewhere within the buffer.
	 * @return false otherwise.
	 */
	bool overlaps(const_pointer p)const noexcept{
		return this->begin() <= p && p <= (this->end() - 1);
	}

	friend std::ostream& operator<<(std::ostream& s, const span<T>& buf){
		for(auto& e : buf){
			s << e;
		}
		return s;
	}
};

template <class T> inline utki::span<T> make_span(nullptr_t){
	return utki::span<T>(nullptr);
}

template <class T> inline utki::span<T> make_span(T* buf, size_t size){
	return utki::span<T>(buf, size);
}

template <class T> inline const utki::span<T> make_span(const T* buf, size_t size){
	return utki::span<T>(const_cast<T*>(buf), size);
}

template <class T, std::size_t array_size> inline utki::span<T> make_span(std::array<T, array_size>& a){
	return make_span(a.size() == 0 ? nullptr : &*a.begin(), a.size());
}

template <class T, std::size_t array_size> inline const utki::span<T> make_span(const std::array<T, array_size>& a){
	return make_span(a.size() == 0 ? nullptr : &*a.begin(), a.size());
}

template <class T> inline utki::span<T> make_span(std::vector<T>& v){
	return make_span(v.size() == 0 ? nullptr : &*v.begin(), v.size());
}

template <class T> inline const utki::span<T> make_span(const std::vector<T>& v){
	return make_span(v.size() == 0 ? nullptr : &*v.begin(), v.size());
}

inline std::string to_string(const utki::span<char>& buf){
	return std::string(buf.data(), buf.size());
}

}
<|endoftext|>


<commit_before>// operations with variables
#include <iostream>

int main()
{
  // declaring variables
  int a, b;
  int result;

  // process
  a = 5;
  b = 2;
  a = a + 1;
  result = a - b;

  // print the result
  std::cout << result << std::endl;

  // terminate the program
  return 0;
}
<commit_msg>add few more manipulations on variables<commit_after>// operations with variables
#include <iostream>
#include <string>

int main()
{
  // declaring variables
  int a = 0;      // c-like initialization
  int b (0);      // constructor initialization
  int result {0}; // uniform initialization

  int foo (0);
  auto bar (foo); // compiler will determine bar's type
  decltype(foo) baar;
  decltype(foo) baar2 (5);

  // simulate use
  (void)bar;
  (void)baar;
  // actual use
  std::cout << baar2 << std::endl;

  // process
  a = 5;
  b = 2;
  a = a + 1;
  result = a - b;

  // print the result
  std::cout << result << std::endl;

  // using strings
  std::string oneString ("So this is what a string looks like");

  std::cout << oneString << std::endl;
  // terminate the program
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <fs.h>
#include <logging.h>
#include <wallet/db.h>

#include <string>

std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
{
    const size_t offset = wallet_dir.string().size() + 1;
    std::vector<fs::path> paths;
    boost::system::error_code ec;

    for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) {
        if (ec) {
            LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string());
            continue;
        }

        try {
            // Get wallet path relative to walletdir by removing walletdir from the wallet path.
            // This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60.
            const fs::path path = it->path().string().substr(offset);

            if (it->status().type() == fs::directory_file &&
                (IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) {
                // Found a directory which contains wallet.dat btree file, add it as a wallet.
                paths.emplace_back(path);
            } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && IsBDBFile(it->path())) {
                if (it->path().filename() == "wallet.dat") {
                    // Found top-level wallet.dat btree file, add top level directory ""
                    // as a wallet.
                    paths.emplace_back();
                } else {
                    // Found top-level btree file not called wallet.dat. Current bitcoin
                    // software will never create these files but will allow them to be
                    // opened in a shared database environment for backwards compatibility.
                    // Add it to the list of available wallets.
                    paths.emplace_back(path);
                }
            }
        } catch (const std::exception& e) {
            LogPrintf("%s: Error scanning %s: %s\n", __func__, it->path().string(), e.what());
            it.no_push();
        }
    }

    return paths;
}

fs::path BDBDataFile(const fs::path& wallet_path)
{
    if (fs::is_regular_file(wallet_path)) {
        // Special case for backwards compatibility: if wallet path points to an
        // existing file, treat it as the path to a BDB data file in a parent
        // directory that also contains BDB log files.
        return wallet_path;
    } else {
        // Normal case: Interpret wallet path as a directory path containing
        // data and log files.
        return wallet_path / "wallet.dat";
    }
}

fs::path SQLiteDataFile(const fs::path& path)
{
    return path / "wallet.dat";
}

bool IsBDBFile(const fs::path& path)
{
    if (!fs::exists(path)) return false;

    // A Berkeley DB Btree file has at least 4K.
    // This check also prevents opening lock files.
    boost::system::error_code ec;
    auto size = fs::file_size(path, ec);
    if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
    if (size < 4096) return false;

    fsbridge::ifstream file(path, std::ios::binary);
    if (!file.is_open()) return false;

    file.seekg(12, std::ios::beg); // Magic bytes start at offset 12
    uint32_t data = 0;
    file.read((char*) &data, sizeof(data)); // Read 4 bytes of file to compare against magic

    // Berkeley DB Btree magic bytes, from:
    //  https://github.com/file/file/blob/5824af38469ec1ca9ac3ffd251e7afe9dc11e227/magic/Magdir/database#L74-L75
    //  - big endian systems - 00 05 31 62
    //  - little endian systems - 62 31 05 00
    return data == 0x00053162 || data == 0x62310500;
}

bool IsSQLiteFile(const fs::path& path)
{
    if (!fs::exists(path)) return false;

    // A SQLite Database file is at least 512 bytes.
    boost::system::error_code ec;
    auto size = fs::file_size(path, ec);
    if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
    if (size < 512) return false;

    fsbridge::ifstream file(path, std::ios::binary);
    if (!file.is_open()) return false;

    // Magic is at beginning and is 16 bytes long
    char magic[16];
    file.read(magic, 16);

    // Application id is at offset 68 and 4 bytes long
    file.seekg(68, std::ios::beg);
    char app_id[4];
    file.read(app_id, 4);

    file.close();

    // Check the magic, see https://sqlite.org/fileformat2.html
    std::string magic_str(magic, 16);
    if (magic_str != std::string("SQLite format 3", 16)) {
        return false;
    }

    // Check the application id matches our network magic
    return memcmp(Params().MessageStart(), app_id, 4) == 0;
}
<commit_msg>wallet: Do not iterate a directory if having an error while accessing it<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <fs.h>
#include <logging.h>
#include <wallet/db.h>

#include <string>

std::vector<fs::path> ListDatabases(const fs::path& wallet_dir)
{
    const size_t offset = wallet_dir.string().size() + 1;
    std::vector<fs::path> paths;
    boost::system::error_code ec;

    for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) {
        if (ec) {
            if (fs::is_directory(*it)) {
                it.no_push();
                LogPrintf("%s: %s %s -- skipping.\n", __func__, ec.message(), it->path().string());
            } else {
                LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string());
            }
            continue;
        }

        try {
            // Get wallet path relative to walletdir by removing walletdir from the wallet path.
            // This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60.
            const fs::path path = it->path().string().substr(offset);

            if (it->status().type() == fs::directory_file &&
                (IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) {
                // Found a directory which contains wallet.dat btree file, add it as a wallet.
                paths.emplace_back(path);
            } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && IsBDBFile(it->path())) {
                if (it->path().filename() == "wallet.dat") {
                    // Found top-level wallet.dat btree file, add top level directory ""
                    // as a wallet.
                    paths.emplace_back();
                } else {
                    // Found top-level btree file not called wallet.dat. Current bitcoin
                    // software will never create these files but will allow them to be
                    // opened in a shared database environment for backwards compatibility.
                    // Add it to the list of available wallets.
                    paths.emplace_back(path);
                }
            }
        } catch (const std::exception& e) {
            LogPrintf("%s: Error scanning %s: %s\n", __func__, it->path().string(), e.what());
            it.no_push();
        }
    }

    return paths;
}

fs::path BDBDataFile(const fs::path& wallet_path)
{
    if (fs::is_regular_file(wallet_path)) {
        // Special case for backwards compatibility: if wallet path points to an
        // existing file, treat it as the path to a BDB data file in a parent
        // directory that also contains BDB log files.
        return wallet_path;
    } else {
        // Normal case: Interpret wallet path as a directory path containing
        // data and log files.
        return wallet_path / "wallet.dat";
    }
}

fs::path SQLiteDataFile(const fs::path& path)
{
    return path / "wallet.dat";
}

bool IsBDBFile(const fs::path& path)
{
    if (!fs::exists(path)) return false;

    // A Berkeley DB Btree file has at least 4K.
    // This check also prevents opening lock files.
    boost::system::error_code ec;
    auto size = fs::file_size(path, ec);
    if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
    if (size < 4096) return false;

    fsbridge::ifstream file(path, std::ios::binary);
    if (!file.is_open()) return false;

    file.seekg(12, std::ios::beg); // Magic bytes start at offset 12
    uint32_t data = 0;
    file.read((char*) &data, sizeof(data)); // Read 4 bytes of file to compare against magic

    // Berkeley DB Btree magic bytes, from:
    //  https://github.com/file/file/blob/5824af38469ec1ca9ac3ffd251e7afe9dc11e227/magic/Magdir/database#L74-L75
    //  - big endian systems - 00 05 31 62
    //  - little endian systems - 62 31 05 00
    return data == 0x00053162 || data == 0x62310500;
}

bool IsSQLiteFile(const fs::path& path)
{
    if (!fs::exists(path)) return false;

    // A SQLite Database file is at least 512 bytes.
    boost::system::error_code ec;
    auto size = fs::file_size(path, ec);
    if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
    if (size < 512) return false;

    fsbridge::ifstream file(path, std::ios::binary);
    if (!file.is_open()) return false;

    // Magic is at beginning and is 16 bytes long
    char magic[16];
    file.read(magic, 16);

    // Application id is at offset 68 and 4 bytes long
    file.seekg(68, std::ios::beg);
    char app_id[4];
    file.read(app_id, 4);

    file.close();

    // Check the magic, see https://sqlite.org/fileformat2.html
    std::string magic_str(magic, 16);
    if (magic_str != std::string("SQLite format 3", 16)) {
        return false;
    }

    // Check the application id matches our network magic
    return memcmp(Params().MessageStart(), app_id, 4) == 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-present Facebook, Inc.
 *
 * 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 <folly/Benchmark.h>

#include <thrift/lib/cpp/transport/TBufferTransports.h>
#include <thrift/lib/cpp/protocol/TBinaryProtocol.h>
#include <thrift/lib/cpp/protocol/THeaderProtocol.h>

#include <thrift/test/gen-cpp/DebugProtoTest_types.h>

#include <gflags/gflags.h>

using namespace boost;
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
using namespace thrift::test::debug;

/** An adaptor class that maps the Duplex THeaderProtocolFactory back to a
 * TProtocolFactory
 */
class TSingleHeaderProtocolFactory : public TProtocolFactory {
 public:
  TSingleHeaderProtocolFactory() {}

  ~TSingleHeaderProtocolFactory() override {}

  std::shared_ptr<TProtocol> getProtocol(
      std::shared_ptr<TTransport> trans) override {
    TProtocolPair protocols = factory_.getProtocol(trans);
    return protocols.first;
  }

 private:
  THeaderProtocolFactory factory_;
};

template <class Protocol_>
void WriteOneOfEach(TProtocolFactory& prot_factory, int iters) {
  OneOfEach ooe;
  ooe.im_true   = true;
  ooe.im_false  = false;
  ooe.a_bite    = 0xd6;
  ooe.integer16 = 27000;
  ooe.integer32 = 1<<24;
  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
  ooe.double_precision = M_PI;
  ooe.some_characters  = "JSON THIS! \"\1";
  ooe.zomg_unicode     = "\xd7\n\a\t";
  ooe.base64 = "\1\2\3\255";
  ooe.string_string_map["one"] = "two";
  ooe.string_string_hash_map["three"] = "four";
  ooe.float_precision = (float)12.345;
  ooe.rank_map[567419810] = (float)0.211184;
  ooe.rank_map[507959914] = (float)0.080382;
  std::shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer());
  std::shared_ptr<TProtocol> generic_prot(prot_factory.getProtocol(buf));

  Protocol_* prot = dynamic_cast<Protocol_*>(generic_prot.get());
  if (!prot) {
    abort();
  }

  for (int i = 0; i < iters; ++i) {
    buf->resetBuffer();
    ooe.write(prot);
    prot->getTransport()->flush();
  }
}

template <class Protocol_>
void ReadOneOfEach(TProtocolFactory& prot_factory, int iters) {
  OneOfEach ooe;
  ooe.im_true   = true;
  ooe.im_false  = false;
  ooe.a_bite    = 0xd6;
  ooe.integer16 = 27000;
  ooe.integer32 = 1<<24;
  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
  ooe.double_precision = M_PI;
  ooe.some_characters  = "JSON THIS! \"\1";
  ooe.zomg_unicode     = "\xd7\n\a\t";
  ooe.base64 = "\1\2\3\255";
  ooe.string_string_map["one"] = "two";
  ooe.string_string_hash_map["three"] = "four";
  ooe.float_precision = (float)12.345;
  ooe.rank_map[567419810] = (float)0.211184;
  ooe.rank_map[507959914] = (float)0.080382;

  std::shared_ptr<TMemoryBuffer> rbuf(new TMemoryBuffer());
  std::shared_ptr<TMemoryBuffer> wbuf(new TMemoryBuffer());
  std::shared_ptr<TProtocol> generic_iprot(prot_factory.getProtocol(rbuf));
  std::shared_ptr<TProtocol> generic_oprot(prot_factory.getProtocol(wbuf));

  Protocol_* iprot = dynamic_cast<Protocol_*>(generic_iprot.get());
  Protocol_* oprot = dynamic_cast<Protocol_*>(generic_oprot.get());
  if (!iprot || !oprot) {
    abort();
  }

  ooe.write(oprot);
  oprot->getTransport()->flush();
  uint8_t* data;
  uint32_t datasize;
  wbuf->getBuffer(&data, &datasize);

  // Don't construct a new OneOfEach object each time around the loop.
  // The vector insert operations in the constructor take up a significant
  // fraction of the time.
  OneOfEach ooe2;
  for (int i = 0; i < iters; ++i) {
      rbuf->resetBuffer(data, datasize);
      ooe2.read(iprot);
  }
}

BENCHMARK(BM_WriteFullyTemplatized, iters) {
  // Test with TBinaryProtocolT<TBufferBase>,
  // and OneOfEach.write< TBinaryProtocolT<TBufferBase> >
  TBinaryProtocolFactoryT<TBufferBase> prot_factory;
  WriteOneOfEach< TBinaryProtocolT<TBufferBase> >(prot_factory, iters);
}

BENCHMARK(BM_WriteTransportTemplatized, iters) {
  // Test with TBinaryProtocolT<TBufferBase>,
  // but OneOfEach.write<TProtocol>
  TBinaryProtocolFactoryT<TBufferBase> prot_factory;
  WriteOneOfEach<TProtocol>(prot_factory, iters);
}

BENCHMARK(BM_WriteProtocolTemplatized, iters) {
  // Test with TBinaryProtocol and OneOfEach.write<TBinaryProtocol>
  TBinaryProtocolFactory prot_factory;
  WriteOneOfEach<TBinaryProtocol>(prot_factory, iters);
}

BENCHMARK(BM_WriteGeneric, iters) {
  // Test with TBinaryProtocol and OneOfEach.write<TProtocol>
  TBinaryProtocolFactory prot_factory;
  WriteOneOfEach<TProtocol>(prot_factory, iters);
}

BENCHMARK(BM_WriteHeaderGeneric, iters) {
  // Test with TBinaryProtocol and OneOfEach.write<TProtocol>
  TSingleHeaderProtocolFactory prot_factory;
  WriteOneOfEach<THeaderProtocol>(prot_factory, iters);
}

BENCHMARK(BM_ReadFullyTemplatized, iters) {
  // Test with TBinaryProtocolT<TBufferBase>,
  // and OneOfEach.write< TBinaryProtocolT<TBufferBase> >
  TBinaryProtocolFactoryT<TBufferBase> prot_factory;
  ReadOneOfEach< TBinaryProtocolT<TBufferBase> >(prot_factory, iters);
}

BENCHMARK(BM_ReadTransportTemplatized, iters) {
  // Test with TBinaryProtocolT<TBufferBase>,
  // but OneOfEach.write<TProtocol>
  TBinaryProtocolFactoryT<TBufferBase> prot_factory;
  ReadOneOfEach<TProtocol>(prot_factory, iters);
}

BENCHMARK(BM_ReadProtocolTemplatized, iters) {
  // Test with TBinaryProtocol and OneOfEach.write<TBinaryProtocol>
  TBinaryProtocolFactory prot_factory;
  ReadOneOfEach<TBinaryProtocol>(prot_factory, iters);
}

BENCHMARK(BM_ReadGeneric, iters) {
  // Test with TBinaryProtocolT<TTransport> and OneOfEach.write<TProtocol>
  TBinaryProtocolFactory prot_factory;
  ReadOneOfEach<TProtocol>(prot_factory, iters);
}

BENCHMARK(BM_ReadHeaderGeneric, iters) {
  // Test with TBinaryProtocolT<TTransport> and OneOfEach.write<TProtocol>
  TSingleHeaderProtocolFactory prot_factory;
  ReadOneOfEach<THeaderProtocol>(prot_factory, iters);
}

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);

  // Run the benchmarks
  folly::runBenchmarksOnFlag();

  return 0;
}
<commit_msg>Cut dead/legacy thrift/test/FbBenchmark.cpp<commit_after><|endoftext|>


<commit_before>/*
 *  Copyright 2008-2013 NVIDIA Corporation
 *
 *  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 <thrust/detail/config.h>
#include <thrust/detail/reference.h>
#include <thrust/detail/type_traits.h>
#include <thrust/iterator/iterator_traits.h>
#include <thrust/system/detail/generic/select_system.h>
#include <thrust/system/detail/generic/memory.h>
#include <thrust/system/detail/adl/get_value.h>
#include <thrust/system/detail/adl/assign_value.h>
#include <thrust/system/detail/adl/iter_swap.h>

namespace thrust
{

template<typename Element, typename Pointer, typename Derived>
  template<typename OtherElement, typename OtherPointer, typename OtherDerived>
    __host__ __device__
    reference<Element,Pointer,Derived>
      ::reference(const reference<OtherElement,OtherPointer,OtherDerived> &other,
                  typename thrust::detail::enable_if_convertible<
                    typename reference<OtherElement,OtherPointer,OtherDerived>::pointer,
                    pointer
                  >::type *)
        : m_ptr(other.m_ptr)
{}

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  reference<Element,Pointer,Derived>
    ::reference(const pointer &ptr)
      : m_ptr(ptr)
{}

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  typename reference<Element,Pointer,Derived>::pointer
    reference<Element,Pointer,Derived>
      ::operator&() const
{
  return m_ptr;
} // end reference::operator&()

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator=(const value_type &v)
{
  assign_from(&v);
  return static_cast<derived_type&>(*this);
} // end reference::operator=()

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator=(const reference &other)
{
  assign_from(&other);
  return static_cast<derived_type&>(*this);
} // end reference::operator=()

template<typename Element, typename Pointer, typename Derived>
  template<typename OtherElement, typename OtherPointer, typename OtherDerived>
    __host__ __device__
    typename reference<Element,Pointer,Derived>::derived_type &
      reference<Element,Pointer,Derived>
        ::operator=(const reference<OtherElement,OtherPointer,OtherDerived> &other)
{
  assign_from(&other);
  return static_cast<derived_type&>(*this);
} // end reference::operator=()

template<typename Element, typename Pointer, typename Derived>
  template<typename System>
    typename reference<Element,Pointer,Derived>::value_type
      reference<Element,Pointer,Derived>
        ::convert_to_value_type(System *system) const
{
  using thrust::system::detail::generic::select_system;
  return strip_const_get_value(select_system(*system));
} // end convert_to_value_type()

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  reference<Element,Pointer,Derived>
    ::operator typename reference<Element,Pointer,Derived>::value_type () const
{
  typedef typename thrust::iterator_system<pointer>::type System;

  // XXX avoid default-constructing a system
  // XXX use null a reference for dispatching
  // XXX this assumes that the eventual invocation of
  // XXX get_value will not access system state
  System *system = 0;

  return convert_to_value_type(system);
} // end reference::operator value_type ()

template<typename Element, typename Pointer, typename Derived>
  template<typename System>
    __host__ __device__
    typename reference<Element,Pointer,Derived>::value_type
      reference<Element,Pointer,Derived>
        ::strip_const_get_value(const System &system) const
{
  System &non_const_system = const_cast<System&>(system);

  using thrust::system::detail::generic::get_value;

  return get_value(thrust::detail::derived_cast(non_const_system), m_ptr);
} // end reference::strip_const_get_value()

template<typename Element, typename Pointer, typename Derived>
  template<typename System1, typename System2, typename OtherPointer>
    void reference<Element,Pointer,Derived>
      ::assign_from(System1 *system1, System2 *system2, OtherPointer src)
{
  using thrust::system::detail::generic::select_system;

  strip_const_assign_value(select_system(*system1, *system2), src);
} // end assign_from()

template<typename Element, typename Pointer, typename Derived>
  template<typename OtherPointer>
    __host__ __device__
    void reference<Element,Pointer,Derived>
      ::assign_from(OtherPointer src)
{
  typedef typename thrust::iterator_system<pointer>::type      System1;
  typedef typename thrust::iterator_system<OtherPointer>::type System2;

  // XXX avoid default-constructing a system
  // XXX use null references for dispatching
  // XXX this assumes that the eventual invocation of
  // XXX assign_value will not access system state
  System1 *system1 = 0;
  System2 *system2 = 0;

  assign_from(system1, system2, src);
} // end assign_from()

template<typename Element, typename Pointer, typename Derived>
  template<typename System, typename OtherPointer>
    __host__ __device__
    void reference<Element,Pointer,Derived>
      ::strip_const_assign_value(const System &system, OtherPointer src)
{
  System &non_const_system = const_cast<System&>(system);

  using thrust::system::detail::generic::assign_value;

  assign_value(thrust::detail::derived_cast(non_const_system), m_ptr, src);
} // end strip_const_assign_value()

template<typename Element, typename Pointer, typename Derived>
  template<typename System>
    void reference<Element,Pointer,Derived>
      ::swap(System *system, derived_type &other)
{
  using thrust::system::detail::generic::select_system;
  using thrust::system::detail::generic::iter_swap;

  iter_swap(select_system(*system, *system), m_ptr, other.m_ptr);
} // end reference::swap()

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  void reference<Element,Pointer,Derived>
    ::swap(derived_type &other)
{
  typedef typename thrust::iterator_system<pointer>::type System;

  // XXX avoid default-constructing a system
  // XXX use null references for dispatching
  // XXX this assumes that the eventual invocation
  // XXX of iter_swap will not access system state
  System *system = 0;

  swap(system, other);
} // end reference::swap()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator++(void)
{
  value_type temp = *this;
  ++temp;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator++()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::value_type
    reference<Element,Pointer,Derived>
      ::operator++(int)
{
  value_type temp = *this;
  value_type result = temp++;
  *this = temp;
  return result;
} // end reference::operator++()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator+=(const value_type &rhs)
{
  value_type temp = *this;
  temp += rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator+=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator--(void)
{
  value_type temp = *this;
  --temp;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator--()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::value_type
    reference<Element,Pointer,Derived>
      ::operator--(int)
{
  value_type temp = *this;
  value_type result = temp--;
  *this = temp;
  return result;
} // end reference::operator--()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator-=(const value_type &rhs)
{
  value_type temp = *this;
  temp -= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator-=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator*=(const value_type &rhs)
{
  value_type temp = *this;
  temp *= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator*=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator/=(const value_type &rhs)
{
  value_type temp = *this;
  temp /= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator/=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator%=(const value_type &rhs)
{
  value_type temp = *this;
  temp %= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator%=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator<<=(const value_type &rhs)
{
  value_type temp = *this;
  temp <<= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator<<=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator>>=(const value_type &rhs)
{
  value_type temp = *this;
  temp >>= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator>>=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator&=(const value_type &rhs)
{
  value_type temp = *this;
  temp &= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator&=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator|=(const value_type &rhs)
{
  value_type temp = *this;
  temp |= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator|=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator^=(const value_type &rhs)
{
  value_type temp = *this;
  temp ^= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator^=()

template<typename Element, typename Pointer, typename Derived,
         typename charT, typename traits>
std::basic_ostream<charT, traits> &
operator<<(std::basic_ostream<charT, traits> &os,
           const reference<Element, Pointer, Derived> &y) {
  typedef typename reference<Element, Pointer, Derived>::value_type value_type;
  return os << static_cast<value_type>(y);
} // end operator<<()

} // end thrust
<commit_msg>Sync attributes of reference::assign_from definitions with their declarations.<commit_after>/*
 *  Copyright 2008-2013 NVIDIA Corporation
 *
 *  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 <thrust/detail/config.h>
#include <thrust/detail/reference.h>
#include <thrust/detail/type_traits.h>
#include <thrust/iterator/iterator_traits.h>
#include <thrust/system/detail/generic/select_system.h>
#include <thrust/system/detail/generic/memory.h>
#include <thrust/system/detail/adl/get_value.h>
#include <thrust/system/detail/adl/assign_value.h>
#include <thrust/system/detail/adl/iter_swap.h>

namespace thrust
{

template<typename Element, typename Pointer, typename Derived>
  template<typename OtherElement, typename OtherPointer, typename OtherDerived>
    __host__ __device__
    reference<Element,Pointer,Derived>
      ::reference(const reference<OtherElement,OtherPointer,OtherDerived> &other,
                  typename thrust::detail::enable_if_convertible<
                    typename reference<OtherElement,OtherPointer,OtherDerived>::pointer,
                    pointer
                  >::type *)
        : m_ptr(other.m_ptr)
{}

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  reference<Element,Pointer,Derived>
    ::reference(const pointer &ptr)
      : m_ptr(ptr)
{}

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  typename reference<Element,Pointer,Derived>::pointer
    reference<Element,Pointer,Derived>
      ::operator&() const
{
  return m_ptr;
} // end reference::operator&()

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator=(const value_type &v)
{
  assign_from(&v);
  return static_cast<derived_type&>(*this);
} // end reference::operator=()

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator=(const reference &other)
{
  assign_from(&other);
  return static_cast<derived_type&>(*this);
} // end reference::operator=()

template<typename Element, typename Pointer, typename Derived>
  template<typename OtherElement, typename OtherPointer, typename OtherDerived>
    __host__ __device__
    typename reference<Element,Pointer,Derived>::derived_type &
      reference<Element,Pointer,Derived>
        ::operator=(const reference<OtherElement,OtherPointer,OtherDerived> &other)
{
  assign_from(&other);
  return static_cast<derived_type&>(*this);
} // end reference::operator=()

template<typename Element, typename Pointer, typename Derived>
  template<typename System>
    __host__ __device__
    typename reference<Element,Pointer,Derived>::value_type
      reference<Element,Pointer,Derived>
        ::convert_to_value_type(System *system) const
{
  using thrust::system::detail::generic::select_system;
  return strip_const_get_value(select_system(*system));
} // end convert_to_value_type()

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  reference<Element,Pointer,Derived>
    ::operator typename reference<Element,Pointer,Derived>::value_type () const
{
  typedef typename thrust::iterator_system<pointer>::type System;

  // XXX avoid default-constructing a system
  // XXX use null a reference for dispatching
  // XXX this assumes that the eventual invocation of
  // XXX get_value will not access system state
  System *system = 0;

  return convert_to_value_type(system);
} // end reference::operator value_type ()

template<typename Element, typename Pointer, typename Derived>
  template<typename System>
    __host__ __device__
    typename reference<Element,Pointer,Derived>::value_type
      reference<Element,Pointer,Derived>
        ::strip_const_get_value(const System &system) const
{
  System &non_const_system = const_cast<System&>(system);

  using thrust::system::detail::generic::get_value;

  return get_value(thrust::detail::derived_cast(non_const_system), m_ptr);
} // end reference::strip_const_get_value()

template<typename Element, typename Pointer, typename Derived>
  template<typename System1, typename System2, typename OtherPointer>
    __host__ __device__
    void reference<Element,Pointer,Derived>
      ::assign_from(System1 *system1, System2 *system2, OtherPointer src)
{
  using thrust::system::detail::generic::select_system;

  strip_const_assign_value(select_system(*system1, *system2), src);
} // end assign_from()

template<typename Element, typename Pointer, typename Derived>
  template<typename OtherPointer>
    __host__ __device__
    void reference<Element,Pointer,Derived>
      ::assign_from(OtherPointer src)
{
  typedef typename thrust::iterator_system<pointer>::type      System1;
  typedef typename thrust::iterator_system<OtherPointer>::type System2;

  // XXX avoid default-constructing a system
  // XXX use null references for dispatching
  // XXX this assumes that the eventual invocation of
  // XXX assign_value will not access system state
  System1 *system1 = 0;
  System2 *system2 = 0;

  assign_from(system1, system2, src);
} // end assign_from()

template<typename Element, typename Pointer, typename Derived>
  template<typename System, typename OtherPointer>
    __host__ __device__
    void reference<Element,Pointer,Derived>
      ::strip_const_assign_value(const System &system, OtherPointer src)
{
  System &non_const_system = const_cast<System&>(system);

  using thrust::system::detail::generic::assign_value;

  assign_value(thrust::detail::derived_cast(non_const_system), m_ptr, src);
} // end strip_const_assign_value()

template<typename Element, typename Pointer, typename Derived>
  template<typename System>
    void reference<Element,Pointer,Derived>
      ::swap(System *system, derived_type &other)
{
  using thrust::system::detail::generic::select_system;
  using thrust::system::detail::generic::iter_swap;

  iter_swap(select_system(*system, *system), m_ptr, other.m_ptr);
} // end reference::swap()

template<typename Element, typename Pointer, typename Derived>
  __host__ __device__
  void reference<Element,Pointer,Derived>
    ::swap(derived_type &other)
{
  typedef typename thrust::iterator_system<pointer>::type System;

  // XXX avoid default-constructing a system
  // XXX use null references for dispatching
  // XXX this assumes that the eventual invocation
  // XXX of iter_swap will not access system state
  System *system = 0;

  swap(system, other);
} // end reference::swap()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator++(void)
{
  value_type temp = *this;
  ++temp;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator++()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::value_type
    reference<Element,Pointer,Derived>
      ::operator++(int)
{
  value_type temp = *this;
  value_type result = temp++;
  *this = temp;
  return result;
} // end reference::operator++()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator+=(const value_type &rhs)
{
  value_type temp = *this;
  temp += rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator+=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator--(void)
{
  value_type temp = *this;
  --temp;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator--()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::value_type
    reference<Element,Pointer,Derived>
      ::operator--(int)
{
  value_type temp = *this;
  value_type result = temp--;
  *this = temp;
  return result;
} // end reference::operator--()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator-=(const value_type &rhs)
{
  value_type temp = *this;
  temp -= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator-=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator*=(const value_type &rhs)
{
  value_type temp = *this;
  temp *= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator*=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator/=(const value_type &rhs)
{
  value_type temp = *this;
  temp /= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator/=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator%=(const value_type &rhs)
{
  value_type temp = *this;
  temp %= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator%=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator<<=(const value_type &rhs)
{
  value_type temp = *this;
  temp <<= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator<<=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator>>=(const value_type &rhs)
{
  value_type temp = *this;
  temp >>= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator>>=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator&=(const value_type &rhs)
{
  value_type temp = *this;
  temp &= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator&=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator|=(const value_type &rhs)
{
  value_type temp = *this;
  temp |= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator|=()

template<typename Element, typename Pointer, typename Derived>
  typename reference<Element,Pointer,Derived>::derived_type &
    reference<Element,Pointer,Derived>
      ::operator^=(const value_type &rhs)
{
  value_type temp = *this;
  temp ^= rhs;
  *this = temp;
  return static_cast<derived_type&>(*this);
} // end reference::operator^=()

template<typename Element, typename Pointer, typename Derived,
         typename charT, typename traits>
std::basic_ostream<charT, traits> &
operator<<(std::basic_ostream<charT, traits> &os,
           const reference<Element, Pointer, Derived> &y) {
  typedef typename reference<Element, Pointer, Derived>::value_type value_type;
  return os << static_cast<value_type>(y);
} // end operator<<()

} // end thrust
<|endoftext|>