<commit_before>//===- Local.cpp - Unit tests for Local -----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Utils/Local.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"

using namespace llvm;

TEST(Local, RecursivelyDeleteDeadPHINodes) {
  LLVMContext C;

  IRBuilder<> builder(C);

  // Make blocks
  BasicBlock *bb0 = BasicBlock::Create(C);
  BasicBlock *bb1 = BasicBlock::Create(C);

  builder.SetInsertPoint(bb0);
  PHINode    *phi = builder.CreatePHI(Type::getInt32Ty(C), 2);
  BranchInst *br0 = builder.CreateCondBr(builder.getTrue(), bb0, bb1);

  builder.SetInsertPoint(bb1);
  BranchInst *br1 = builder.CreateBr(bb0);

  phi->addIncoming(phi, bb0);
  phi->addIncoming(phi, bb1);

  // The PHI will be removed
  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  // Make sure the blocks only contain the branches
  EXPECT_EQ(&bb0->front(), br0);
  EXPECT_EQ(&bb1->front(), br1);

  builder.SetInsertPoint(bb0);
  phi = builder.CreatePHI(Type::getInt32Ty(C), 0);

  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  builder.SetInsertPoint(bb0);
  phi = builder.CreatePHI(Type::getInt32Ty(C), 0);
  builder.CreateAdd(phi, phi);

  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  bb0->dropAllReferences();
  bb1->dropAllReferences();
  delete bb0;
  delete bb1;
}

TEST(Local, RemoveDuplicatePHINodes) {
  LLVMContext C;
  IRBuilder<> B(C);

  std::unique_ptr<Function> F(
      Function::Create(FunctionType::get(B.getVoidTy(), false),
                       GlobalValue::ExternalLinkage, "F"));
  BasicBlock *Entry(BasicBlock::Create(C, "", F.get()));
  BasicBlock *BB(BasicBlock::Create(C, "", F.get()));
  BranchInst::Create(BB, Entry);

  B.SetInsertPoint(BB);

  AssertingVH<PHINode> P1 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P1->addIncoming(B.getInt32(42), Entry);

  PHINode *P2 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P2->addIncoming(B.getInt32(42), Entry);

  AssertingVH<PHINode> P3 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P3->addIncoming(B.getInt32(42), Entry);
  P3->addIncoming(B.getInt32(23), BB);

  PHINode *P4 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P4->addIncoming(B.getInt32(42), Entry);
  P4->addIncoming(B.getInt32(23), BB);

  P1->addIncoming(P3, BB);
  P2->addIncoming(P4, BB);
  BranchInst::Create(BB, BB);

  // Verify that we can eliminate PHIs that become duplicates after chaning PHIs
  // downstream.
  EXPECT_TRUE(EliminateDuplicatePHINodes(BB));
  EXPECT_EQ(3U, BB->size());
}

std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
  SMDiagnostic Err;
  std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
  if (!Mod)
    Err.print("UtilsTests", errs());
  return Mod;
}

TEST(Local, ReplaceDbgDeclare) {
  LLVMContext C;

  // Original C source to get debug info for a local variable:
  // void f() { int x; }
  std::unique_ptr<Module> M = parseIR(
      C,
      "define void @f() !dbg !8 {\n"
      "entry:\n"
      "  %x = alloca i32, align 4\n"
      "  call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
      "!DIExpression()), !dbg !13\n"
      "  call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
      "!DIExpression()), !dbg !13\n"
      "  ret void, !dbg !14\n"
      "}\n"
      "declare void @llvm.dbg.declare(metadata, metadata, metadata)\n"
      "!llvm.dbg.cu = !{!0}\n"
      "!llvm.module.flags = !{!3, !4}\n"
      "!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "
      "\"clang version 6.0.0 \", isOptimized: false, runtimeVersion: 0, "
      "emissionKind: FullDebug, enums: !2)\n"
      "!1 = !DIFile(filename: \"t2.c\", directory: \"foo\")\n"
      "!2 = !{}\n"
      "!3 = !{i32 2, !\"Dwarf Version\", i32 4}\n"
      "!4 = !{i32 2, !\"Debug Info Version\", i32 3}\n"
      "!8 = distinct !DISubprogram(name: \"f\", scope: !1, file: !1, line: 1, "
      "type: !9, isLocal: false, isDefinition: true, scopeLine: 1, "
      "isOptimized: false, unit: !0, variables: !2)\n"
      "!9 = !DISubroutineType(types: !10)\n"
      "!10 = !{null}\n"
      "!11 = !DILocalVariable(name: \"x\", scope: !8, file: !1, line: 2, type: "
      "!12)\n"
      "!12 = !DIBasicType(name: \"int\", size: 32, encoding: DW_ATE_signed)\n"
      "!13 = !DILocation(line: 2, column: 7, scope: !8)\n"
      "!14 = !DILocation(line: 3, column: 1, scope: !8)\n");
  auto *GV = M->getNamedValue("f");
  ASSERT_TRUE(GV);
  auto *F = dyn_cast<Function>(GV);
  ASSERT_TRUE(F);
  Instruction *Inst = &F->front().front();
  auto *AI = dyn_cast<AllocaInst>(Inst);
  ASSERT_TRUE(AI);
  Inst = Inst->getNextNode()->getNextNode();
  ASSERT_TRUE(Inst);
  auto *DII = dyn_cast<DbgDeclareInst>(Inst);
  ASSERT_TRUE(DII);
  Value *NewBase = Constant::getNullValue(Type::getInt32PtrTy(C));
  DIBuilder DIB(*M);
  replaceDbgDeclare(AI, NewBase, DII, DIB, DIExpression::NoDeref, 0,
                    DIExpression::NoDeref);

  // There should be exactly two dbg.declares.
  int Declares = 0;
  for (const Instruction &I : F->front())
    if (isa<DbgDeclareInst>(I))
      Declares++;
  EXPECT_EQ(2, Declares);
}

/// Build the dominator tree for the function and run the Test.
static void runWithDomTree(
    Module &M, StringRef FuncName,
    function_ref<void(Function &F, DominatorTree *DT)> Test) {
  auto *F = M.getFunction(FuncName);
  ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
  // Compute the dominator tree for the function.
  DominatorTree DT(*F);
  Test(*F, &DT);
}

TEST(Local, MergeBasicBlockIntoOnlyPred) {
  LLVMContext C;

  std::unique_ptr<Module> M = parseIR(
      C,
      "define i32 @f(i8* %str) {\n"
      "entry:\n"
      "  br label %bb2.i\n"
      "bb2.i:                                            ; preds = %bb4.i, %entry\n"
      "  br i1 false, label %bb4.i, label %base2flt.exit204\n"
      "bb4.i:                                            ; preds = %bb2.i\n"
      "  br i1 false, label %base2flt.exit204, label %bb2.i\n"
      "bb10.i196.bb7.i197_crit_edge:                     ; No predecessors!\n"
      "  br label %bb7.i197\n"
      "bb7.i197:                                         ; preds = %bb10.i196.bb7.i197_crit_edge\n"
      "  %.reg2mem.0 = phi i32 [ %.reg2mem.0, %bb10.i196.bb7.i197_crit_edge ]\n"
      "  br i1 undef, label %base2flt.exit204, label %base2flt.exit204\n"
      "base2flt.exit204:                                 ; preds = %bb7.i197, %bb7.i197, %bb2.i, %bb4.i\n"
      "  ret i32 0\n"
      "}\n");
  runWithDomTree(
      *M, "f", [&](Function &F, DominatorTree *DT) {
        for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
          BasicBlock *BB = &*I++;
          BasicBlock *SinglePred = BB->getSinglePredecessor();
          if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) continue;
          BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());
          if (Term && !Term->isConditional())
            MergeBasicBlockIntoOnlyPred(BB, DT);
        }
        EXPECT_TRUE(DT->verify());
      });
}
<commit_msg>Add tests for ConstantFoldTerminator preserving DomTree<commit_after>//===- Local.cpp - Unit tests for Local -----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Utils/Local.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"

using namespace llvm;

TEST(Local, RecursivelyDeleteDeadPHINodes) {
  LLVMContext C;

  IRBuilder<> builder(C);

  // Make blocks
  BasicBlock *bb0 = BasicBlock::Create(C);
  BasicBlock *bb1 = BasicBlock::Create(C);

  builder.SetInsertPoint(bb0);
  PHINode    *phi = builder.CreatePHI(Type::getInt32Ty(C), 2);
  BranchInst *br0 = builder.CreateCondBr(builder.getTrue(), bb0, bb1);

  builder.SetInsertPoint(bb1);
  BranchInst *br1 = builder.CreateBr(bb0);

  phi->addIncoming(phi, bb0);
  phi->addIncoming(phi, bb1);

  // The PHI will be removed
  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  // Make sure the blocks only contain the branches
  EXPECT_EQ(&bb0->front(), br0);
  EXPECT_EQ(&bb1->front(), br1);

  builder.SetInsertPoint(bb0);
  phi = builder.CreatePHI(Type::getInt32Ty(C), 0);

  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  builder.SetInsertPoint(bb0);
  phi = builder.CreatePHI(Type::getInt32Ty(C), 0);
  builder.CreateAdd(phi, phi);

  EXPECT_TRUE(RecursivelyDeleteDeadPHINode(phi));

  bb0->dropAllReferences();
  bb1->dropAllReferences();
  delete bb0;
  delete bb1;
}

TEST(Local, RemoveDuplicatePHINodes) {
  LLVMContext C;
  IRBuilder<> B(C);

  std::unique_ptr<Function> F(
      Function::Create(FunctionType::get(B.getVoidTy(), false),
                       GlobalValue::ExternalLinkage, "F"));
  BasicBlock *Entry(BasicBlock::Create(C, "", F.get()));
  BasicBlock *BB(BasicBlock::Create(C, "", F.get()));
  BranchInst::Create(BB, Entry);

  B.SetInsertPoint(BB);

  AssertingVH<PHINode> P1 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P1->addIncoming(B.getInt32(42), Entry);

  PHINode *P2 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P2->addIncoming(B.getInt32(42), Entry);

  AssertingVH<PHINode> P3 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P3->addIncoming(B.getInt32(42), Entry);
  P3->addIncoming(B.getInt32(23), BB);

  PHINode *P4 = B.CreatePHI(Type::getInt32Ty(C), 2);
  P4->addIncoming(B.getInt32(42), Entry);
  P4->addIncoming(B.getInt32(23), BB);

  P1->addIncoming(P3, BB);
  P2->addIncoming(P4, BB);
  BranchInst::Create(BB, BB);

  // Verify that we can eliminate PHIs that become duplicates after chaning PHIs
  // downstream.
  EXPECT_TRUE(EliminateDuplicatePHINodes(BB));
  EXPECT_EQ(3U, BB->size());
}

std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
  SMDiagnostic Err;
  std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
  if (!Mod)
    Err.print("UtilsTests", errs());
  return Mod;
}

TEST(Local, ReplaceDbgDeclare) {
  LLVMContext C;

  // Original C source to get debug info for a local variable:
  // void f() { int x; }
  std::unique_ptr<Module> M = parseIR(
      C,
      "define void @f() !dbg !8 {\n"
      "entry:\n"
      "  %x = alloca i32, align 4\n"
      "  call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
      "!DIExpression()), !dbg !13\n"
      "  call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
      "!DIExpression()), !dbg !13\n"
      "  ret void, !dbg !14\n"
      "}\n"
      "declare void @llvm.dbg.declare(metadata, metadata, metadata)\n"
      "!llvm.dbg.cu = !{!0}\n"
      "!llvm.module.flags = !{!3, !4}\n"
      "!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "
      "\"clang version 6.0.0 \", isOptimized: false, runtimeVersion: 0, "
      "emissionKind: FullDebug, enums: !2)\n"
      "!1 = !DIFile(filename: \"t2.c\", directory: \"foo\")\n"
      "!2 = !{}\n"
      "!3 = !{i32 2, !\"Dwarf Version\", i32 4}\n"
      "!4 = !{i32 2, !\"Debug Info Version\", i32 3}\n"
      "!8 = distinct !DISubprogram(name: \"f\", scope: !1, file: !1, line: 1, "
      "type: !9, isLocal: false, isDefinition: true, scopeLine: 1, "
      "isOptimized: false, unit: !0, variables: !2)\n"
      "!9 = !DISubroutineType(types: !10)\n"
      "!10 = !{null}\n"
      "!11 = !DILocalVariable(name: \"x\", scope: !8, file: !1, line: 2, type: "
      "!12)\n"
      "!12 = !DIBasicType(name: \"int\", size: 32, encoding: DW_ATE_signed)\n"
      "!13 = !DILocation(line: 2, column: 7, scope: !8)\n"
      "!14 = !DILocation(line: 3, column: 1, scope: !8)\n");
  auto *GV = M->getNamedValue("f");
  ASSERT_TRUE(GV);
  auto *F = dyn_cast<Function>(GV);
  ASSERT_TRUE(F);
  Instruction *Inst = &F->front().front();
  auto *AI = dyn_cast<AllocaInst>(Inst);
  ASSERT_TRUE(AI);
  Inst = Inst->getNextNode()->getNextNode();
  ASSERT_TRUE(Inst);
  auto *DII = dyn_cast<DbgDeclareInst>(Inst);
  ASSERT_TRUE(DII);
  Value *NewBase = Constant::getNullValue(Type::getInt32PtrTy(C));
  DIBuilder DIB(*M);
  replaceDbgDeclare(AI, NewBase, DII, DIB, DIExpression::NoDeref, 0,
                    DIExpression::NoDeref);

  // There should be exactly two dbg.declares.
  int Declares = 0;
  for (const Instruction &I : F->front())
    if (isa<DbgDeclareInst>(I))
      Declares++;
  EXPECT_EQ(2, Declares);
}

/// Build the dominator tree for the function and run the Test.
static void runWithDomTree(
    Module &M, StringRef FuncName,
    function_ref<void(Function &F, DominatorTree *DT)> Test) {
  auto *F = M.getFunction(FuncName);
  ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
  // Compute the dominator tree for the function.
  DominatorTree DT(*F);
  Test(*F, &DT);
}

TEST(Local, MergeBasicBlockIntoOnlyPred) {
  LLVMContext C;

  std::unique_ptr<Module> M = parseIR(
      C,
      "define i32 @f(i8* %str) {\n"
      "entry:\n"
      "  br label %bb2.i\n"
      "bb2.i:                                            ; preds = %bb4.i, %entry\n"
      "  br i1 false, label %bb4.i, label %base2flt.exit204\n"
      "bb4.i:                                            ; preds = %bb2.i\n"
      "  br i1 false, label %base2flt.exit204, label %bb2.i\n"
      "bb10.i196.bb7.i197_crit_edge:                     ; No predecessors!\n"
      "  br label %bb7.i197\n"
      "bb7.i197:                                         ; preds = %bb10.i196.bb7.i197_crit_edge\n"
      "  %.reg2mem.0 = phi i32 [ %.reg2mem.0, %bb10.i196.bb7.i197_crit_edge ]\n"
      "  br i1 undef, label %base2flt.exit204, label %base2flt.exit204\n"
      "base2flt.exit204:                                 ; preds = %bb7.i197, %bb7.i197, %bb2.i, %bb4.i\n"
      "  ret i32 0\n"
      "}\n");
  runWithDomTree(
      *M, "f", [&](Function &F, DominatorTree *DT) {
        for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
          BasicBlock *BB = &*I++;
          BasicBlock *SinglePred = BB->getSinglePredecessor();
          if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) continue;
          BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());
          if (Term && !Term->isConditional())
            MergeBasicBlockIntoOnlyPred(BB, DT);
        }
        EXPECT_TRUE(DT->verify());
      });
}

TEST(Local, ConstantFoldTerminator) {
  LLVMContext C;

  std::unique_ptr<Module> M = parseIR(
      C,
      "define void @br_same_dest() {\n"
      "entry:\n"
      "  br i1 false, label %bb0, label %bb0\n"
      "bb0:\n"
      "  ret void\n"
      "}\n"
      "\n"
      "define void @br_different_dest() {\n"
      "entry:\n"
      "  br i1 true, label %bb0, label %bb1\n"
      "bb0:\n"
      "  br label %exit\n"
      "bb1:\n"
      "  br label %exit\n"
      "exit:\n"
      "  ret void\n"
      "}\n"
      "\n"
      "define void @switch_2_different_dest() {\n"
      "entry:\n"
      "  switch i32 0, label %default [ i32 0, label %bb0 ]\n"
      "default:\n"
      "  ret void\n"
      "bb0:\n"
      "  ret void\n"
      "}\n"
      "define void @switch_2_different_dest_default() {\n"
      "entry:\n"
      "  switch i32 1, label %default [ i32 0, label %bb0 ]\n"
      "default:\n"
      "  ret void\n"
      "bb0:\n"
      "  ret void\n"
      "}\n"
      "define void @switch_3_different_dest() {\n"
      "entry:\n"
      "  switch i32 0, label %default [ i32 0, label %bb0\n"
      "                                 i32 1, label %bb1 ]\n"
      "default:\n"
      "  ret void\n"
      "bb0:\n"
      "  ret void\n"
      "bb1:\n"
      "  ret void\n"
      "}\n"
      "\n"
      "define void @switch_variable_2_default_dest(i32 %arg) {\n"
      "entry:\n"
      "  switch i32 %arg, label %default [ i32 0, label %default ]\n"
      "default:\n"
      "  ret void\n"
      "}\n"
      "\n"
      "define void @switch_constant_2_default_dest() {\n"
      "entry:\n"
      "  switch i32 1, label %default [ i32 0, label %default ]\n"
      "default:\n"
      "  ret void\n"
      "}\n"
      "\n"
      "define void @switch_constant_3_repeated_dest() {\n"
      "entry:\n"
      "  switch i32 0, label %default [ i32 0, label %bb0\n"
      "                                 i32 1, label %bb0 ]\n"
      " bb0:\n"
      "   ret void\n"
      "default:\n"
      "  ret void\n"
      "}\n"
      "\n"
      "define void @indirectbr() {\n"
      "entry:\n"
      "  indirectbr i8* blockaddress(@indirectbr, %bb0), [label %bb0, label %bb1]\n"
      "bb0:\n"
      "  ret void\n"
      "bb1:\n"
      "  ret void\n"
      "}\n"
      "\n"
      "define void @indirectbr_repeated() {\n"
      "entry:\n"
      "  indirectbr i8* blockaddress(@indirectbr_repeated, %bb0), [label %bb0, label %bb0]\n"
      "bb0:\n"
      "  ret void\n"
      "}\n"
      "\n"
      "define void @indirectbr_unreachable() {\n"
      "entry:\n"
      "  indirectbr i8* blockaddress(@indirectbr_unreachable, %bb0), [label %bb1]\n"
      "bb0:\n"
      "  ret void\n"
      "bb1:\n"
      "  ret void\n"
      "}\n"
      "\n"
    );

  auto CFAllTerminators = [&](Function &F, DominatorTree *DT) {
    DeferredDominance DDT(*DT);
    for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
      BasicBlock *BB = &*I++;
      ConstantFoldTerminator(BB, true, nullptr, &DDT);
    }

    EXPECT_TRUE(DDT.flush().verify());
  };

  runWithDomTree(*M, "br_same_dest", CFAllTerminators);
  runWithDomTree(*M, "br_different_dest", CFAllTerminators);
  runWithDomTree(*M, "switch_2_different_dest", CFAllTerminators);
  runWithDomTree(*M, "switch_2_different_dest_default", CFAllTerminators);
  runWithDomTree(*M, "switch_3_different_dest", CFAllTerminators);
  runWithDomTree(*M, "switch_variable_2_default_dest", CFAllTerminators);
  runWithDomTree(*M, "switch_constant_2_default_dest", CFAllTerminators);
  runWithDomTree(*M, "switch_constant_3_repeated_dest", CFAllTerminators);
  runWithDomTree(*M, "indirectbr", CFAllTerminators);
  runWithDomTree(*M, "indirectbr_repeated", CFAllTerminators);
  runWithDomTree(*M, "indirectbr_unreachable", CFAllTerminators);
}
<|endoftext|>


<commit_before>//===-- ReproducerTest.cpp --------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "llvm/Support/Error.h"
#include "llvm/Testing/Support/Error.h"

#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Reproducer.h"

using namespace llvm;
using namespace lldb_private;
using namespace lldb_private::repro;

class DummyProvider : public repro::Provider<DummyProvider> {
public:
  static constexpr const char *NAME = "dummy";

  DummyProvider(const FileSpec &directory) : Provider(directory) {
    m_info.name = "dummy";
    m_info.files.push_back("dummy.yaml");
  }

  static char ID;
};

class DummyReproducer : public Reproducer {
public:
  DummyReproducer() : Reproducer(){};

  using Reproducer::SetCapture;
  using Reproducer::SetReplay;
};

char DummyProvider::ID = 0;

TEST(ReproducerTest, SetCapture) {
  DummyReproducer reproducer;

  // Initially both generator and loader are unset.
  EXPECT_EQ(nullptr, reproducer.GetGenerator());
  EXPECT_EQ(nullptr, reproducer.GetLoader());

  // Enable capture and check that means we have a generator.
  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                    Succeeded());
  EXPECT_NE(nullptr, reproducer.GetGenerator());
  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetGenerator()->GetRoot());
  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetReproducerPath());

  // Ensure that we cannot enable replay.
  EXPECT_THAT_ERROR(reproducer.SetReplay(FileSpec("/bogus/path")), Failed());
  EXPECT_EQ(nullptr, reproducer.GetLoader());

  // Ensure we can disable the generator again.
  EXPECT_THAT_ERROR(reproducer.SetCapture(llvm::None), Succeeded());
  EXPECT_EQ(nullptr, reproducer.GetGenerator());
  EXPECT_EQ(nullptr, reproducer.GetLoader());
}

TEST(ReproducerTest, SetReplay) {
  DummyReproducer reproducer;

  // Initially both generator and loader are unset.
  EXPECT_EQ(nullptr, reproducer.GetGenerator());
  EXPECT_EQ(nullptr, reproducer.GetLoader());

  // Expected to fail because we can't load the index.
  EXPECT_THAT_ERROR(reproducer.SetReplay(FileSpec("/bogus/path")), Failed());
  // However the loader should still be set, which we check here.
  EXPECT_NE(nullptr, reproducer.GetLoader());

  // Make sure the bogus path is correctly set.
  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetLoader()->GetRoot());
  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetReproducerPath());

  // Ensure that we cannot enable replay.
  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")), Failed());
  EXPECT_EQ(nullptr, reproducer.GetGenerator());
}

TEST(GeneratorTest, Create) {
  DummyReproducer reproducer;

  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                    Succeeded());
  auto &generator = *reproducer.GetGenerator();

  auto *provider = generator.Create<DummyProvider>();
  EXPECT_NE(nullptr, provider);
  EXPECT_EQ(FileSpec("/bogus/path"), provider->GetRoot());
  EXPECT_EQ(std::string("dummy"), provider->GetInfo().name);
  EXPECT_EQ((size_t)1, provider->GetInfo().files.size());
  EXPECT_EQ(std::string("dummy.yaml"), provider->GetInfo().files.front());
}

TEST(GeneratorTest, Get) {
  DummyReproducer reproducer;

  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                    Succeeded());
  auto &generator = *reproducer.GetGenerator();

  auto *provider = generator.Create<DummyProvider>();
  EXPECT_NE(nullptr, provider);

  auto *provider_alt = generator.Get<DummyProvider>();
  EXPECT_EQ(provider, provider_alt);
}

TEST(GeneratorTest, GetOrCreate) {
  DummyReproducer reproducer;

  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                    Succeeded());
  auto &generator = *reproducer.GetGenerator();

  auto &provider = generator.GetOrCreate<DummyProvider>();
  EXPECT_EQ(FileSpec("/bogus/path"), provider.GetRoot());
  EXPECT_EQ(std::string("dummy"), provider.GetInfo().name);
  EXPECT_EQ((size_t)1, provider.GetInfo().files.size());
  EXPECT_EQ(std::string("dummy.yaml"), provider.GetInfo().files.front());

  auto &provider_alt = generator.GetOrCreate<DummyProvider>();
  EXPECT_EQ(&provider, &provider_alt);
}
<commit_msg>[Reproducers] Fix reproducers unittest.<commit_after>//===-- ReproducerTest.cpp --------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "llvm/Support/Error.h"
#include "llvm/Testing/Support/Error.h"

#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Reproducer.h"

using namespace llvm;
using namespace lldb_private;
using namespace lldb_private::repro;

struct DummyInfo {
  static const char *name;
  static const char *file;
};

const char *DummyInfo::name = "dummy";
const char *DummyInfo::file = "dummy.yaml";

class DummyProvider : public repro::Provider<DummyProvider> {
public:
  typedef DummyInfo info;

  DummyProvider(const FileSpec &directory) : Provider(directory) {}

  static char ID;
};

class DummyReproducer : public Reproducer {
public:
  DummyReproducer() : Reproducer(){};

  using Reproducer::SetCapture;
  using Reproducer::SetReplay;
};

char DummyProvider::ID = 0;

TEST(ReproducerTest, SetCapture) {
  DummyReproducer reproducer;

  // Initially both generator and loader are unset.
  EXPECT_EQ(nullptr, reproducer.GetGenerator());
  EXPECT_EQ(nullptr, reproducer.GetLoader());

  // Enable capture and check that means we have a generator.
  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                    Succeeded());
  EXPECT_NE(nullptr, reproducer.GetGenerator());
  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetGenerator()->GetRoot());
  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetReproducerPath());

  // Ensure that we cannot enable replay.
  EXPECT_THAT_ERROR(reproducer.SetReplay(FileSpec("/bogus/path")), Failed());
  EXPECT_EQ(nullptr, reproducer.GetLoader());

  // Ensure we can disable the generator again.
  EXPECT_THAT_ERROR(reproducer.SetCapture(llvm::None), Succeeded());
  EXPECT_EQ(nullptr, reproducer.GetGenerator());
  EXPECT_EQ(nullptr, reproducer.GetLoader());
}

TEST(ReproducerTest, SetReplay) {
  DummyReproducer reproducer;

  // Initially both generator and loader are unset.
  EXPECT_EQ(nullptr, reproducer.GetGenerator());
  EXPECT_EQ(nullptr, reproducer.GetLoader());

  // Expected to fail because we can't load the index.
  EXPECT_THAT_ERROR(reproducer.SetReplay(FileSpec("/bogus/path")), Failed());
  // However the loader should still be set, which we check here.
  EXPECT_NE(nullptr, reproducer.GetLoader());

  // Make sure the bogus path is correctly set.
  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetLoader()->GetRoot());
  EXPECT_EQ(FileSpec("/bogus/path"), reproducer.GetReproducerPath());

  // Ensure that we cannot enable replay.
  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")), Failed());
  EXPECT_EQ(nullptr, reproducer.GetGenerator());
}

TEST(GeneratorTest, Create) {
  DummyReproducer reproducer;

  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                    Succeeded());
  auto &generator = *reproducer.GetGenerator();

  auto *provider = generator.Create<DummyProvider>();
  EXPECT_NE(nullptr, provider);
  EXPECT_EQ(FileSpec("/bogus/path"), provider->GetRoot());
}

TEST(GeneratorTest, Get) {
  DummyReproducer reproducer;

  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                    Succeeded());
  auto &generator = *reproducer.GetGenerator();

  auto *provider = generator.Create<DummyProvider>();
  EXPECT_NE(nullptr, provider);

  auto *provider_alt = generator.Get<DummyProvider>();
  EXPECT_EQ(provider, provider_alt);
}

TEST(GeneratorTest, GetOrCreate) {
  DummyReproducer reproducer;

  EXPECT_THAT_ERROR(reproducer.SetCapture(FileSpec("/bogus/path")),
                    Succeeded());
  auto &generator = *reproducer.GetGenerator();

  auto &provider = generator.GetOrCreate<DummyProvider>();
  EXPECT_EQ(FileSpec("/bogus/path"), provider.GetRoot());

  auto &provider_alt = generator.GetOrCreate<DummyProvider>();
  EXPECT_EQ(&provider, &provider_alt);
}
<|endoftext|>


<commit_before>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>

#include "util.h"
#include "linesrc.h"
#include "linesink.h"

#include <stdexcept>

using namespace std;

static string                   in_file = "-";
static string                   out_file = "-";

static haxpp_linesink           out_ls;

class haxpp_linesourcestack {
    public:
        haxpp_linesourcestack();
        ~haxpp_linesourcestack();
    public:
        void                        allocstack();
        void                        freestack();
        void                        push();
        void                        pop();
        haxpp_linesource&           top();
        const haxpp_linesource&     top() const;
        void                        clear();
        bool                        empty() const;
    private:
        static constexpr size_t     max_source_stack_default = 64;
        size_t                      max_source_stack = max_source_stack_default;
    private:
        haxpp_linesource*           in_ls = NULL;
        ssize_t                     in_ls_sp = -1;
};

haxpp_linesourcestack::haxpp_linesourcestack() {
}

haxpp_linesourcestack::~haxpp_linesourcestack() {
    freestack();
}

void haxpp_linesourcestack::allocstack() {
    if (in_ls == NULL) {
        in_ls = new haxpp_linesource[max_source_stack];
        in_ls_sp = -1;
    }
}

void haxpp_linesourcestack::freestack() {
    if (in_ls != NULL) {
        clear();
        delete[] in_ls;
        in_ls = NULL;
    }
    in_ls_sp = -1;
}

void haxpp_linesourcestack::push() {
    allocstack();

    /* NTS: when in_ls_sp == -1, in_ls_sp+1 == 0 */
    if (size_t(in_ls_sp+1) < max_source_stack)
        in_ls_sp++;
    else
        throw overflow_error("linesourcestack overflow");
}

void haxpp_linesourcestack::pop() {
    /* in_ls_sp >= 0 should mean in_ls != NULL or else this code would not permit in_ls_sp >= 0 */
    if (in_ls_sp >= ssize_t(0))
        in_ls[in_ls_sp--].close();
    else
        throw underflow_error("linesourcestack underflow");
}

haxpp_linesource& haxpp_linesourcestack::top() {
    /* in_ls_sp >= 0 should mean in_ls != NULL or else this code would not permit in_ls_sp >= 0 */
    if (in_ls_sp >= ssize_t(0))
        return in_ls[in_ls_sp];

    throw underflow_error("linesourcestack attempt to read top() when empty");
}

const haxpp_linesource& haxpp_linesourcestack::top() const {
    /* in_ls_sp >= 0 should mean in_ls != NULL or else this code would not permit in_ls_sp >= 0 */
    if (in_ls_sp >= ssize_t(0))
        return in_ls[in_ls_sp];

    throw underflow_error("linesourcestack attempt to read top() when empty");
}

void haxpp_linesourcestack::clear() {
    while (!empty()) pop();
}

bool haxpp_linesourcestack::empty() const {
    /* in_ls_sp >= 0 should mean in_ls != NULL or else this code would not permit in_ls_sp >= 0 */
    return (in_ls_sp == ssize_t(-1));
}

static haxpp_linesourcestack    in_lstk;

static void help() {
    fprintf(stderr,"haxpp infile outfile\n");
}

static int parse_argv(int argc,char **argv) {
    int nwac=0;
    char *a;
    int i=1;

    while (i < argc) {
        a = argv[i++];

        if (*a == '-' && strcmp(a,"-") != 0/*not "-"*/) {
            do { a++; } while (*a == '-');

            if (!strcmp(a,"h") || !strcmp(a,"help")) {
                help();
                return 1;
            }
            else {
                fprintf(stderr,"Unknown switch %s\n",a);
                return 1;
            }
        }
        else {
            switch (nwac++) {
                case 0:
                    in_file = a;
                    break;
                case 1:
                    out_file = a;
                    break;
                default:
                    fprintf(stderr,"Unexpected arg %s\n",a);
                    return 1;
            }
        }
    }

    return 0;
}

int main(int argc,char **argv) {
    if (parse_argv(argc,argv))
        return 1;

    in_lstk.push();
    if (in_file == "-")
        in_lstk.top().setsource(stdin);
    else
        in_lstk.top().setsource(in_file);

    if (!in_lstk.top().open()) {
        fprintf(stderr,"Unable to open infile, %s\n",strerror(errno));
        return 1;
    }

    if (out_file == "-")
        out_ls.setsink(stdout);
    else
        out_ls.setsink(out_file);

    if (!out_ls.open()) {
        fprintf(stderr,"Unable to open outfile, %s\n",strerror(errno));
        return 1;
    }

    while (!in_lstk.top().eof()) {
        char *line = in_lstk.top().readline();
        if (line == nullptr) {
            if (!in_lstk.top().error() && in_lstk.top().eof()) {
                in_lstk.pop();
                if (in_lstk.empty())
                    break;
                else
                    continue;
            }
            else {
                fprintf(stderr,"Problem reading. error=%u eof=%u errno=%s\n",in_lstk.top().error(),in_lstk.top().eof(),strerror(errno));
                return 1;
            }
        }

        if (!out_ls.write(line)) {
            fprintf(stderr,"Error writing output\n");
            return 1;
        }
    }

    if (!in_lstk.empty()) {
        if (in_lstk.top().error()) {
            fprintf(stderr,"An error occurred while parsing %s\n",in_lstk.top().getsourcename().c_str());
            return 1;
        }
    }

    if (out_ls.error()) {
        fprintf(stderr,"An error occurred while parsing %s\n",out_ls.getsinkname().c_str());
        return 1;
    }

    out_ls.close();
    in_lstk.clear();
    return 0;
}

<commit_msg>Send #line directive<commit_after>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>

#include "util.h"
#include "linesrc.h"
#include "linesink.h"

#include <stdexcept>

using namespace std;

static string                   in_file = "-";
static string                   out_file = "-";

static haxpp_linesink           out_ls;

class haxpp_linesourcestack {
    public:
        haxpp_linesourcestack();
        ~haxpp_linesourcestack();
    public:
        void                        allocstack();
        void                        freestack();
        void                        push();
        void                        pop();
        haxpp_linesource&           top();
        const haxpp_linesource&     top() const;
        void                        clear();
        bool                        empty() const;
    private:
        static constexpr size_t     max_source_stack_default = 64;
        size_t                      max_source_stack = max_source_stack_default;
    private:
        haxpp_linesource*           in_ls = NULL;
        ssize_t                     in_ls_sp = -1;
};

haxpp_linesourcestack::haxpp_linesourcestack() {
}

haxpp_linesourcestack::~haxpp_linesourcestack() {
    freestack();
}

void haxpp_linesourcestack::allocstack() {
    if (in_ls == NULL) {
        in_ls = new haxpp_linesource[max_source_stack];
        in_ls_sp = -1;
    }
}

void haxpp_linesourcestack::freestack() {
    if (in_ls != NULL) {
        clear();
        delete[] in_ls;
        in_ls = NULL;
    }
    in_ls_sp = -1;
}

void haxpp_linesourcestack::push() {
    allocstack();

    /* NTS: when in_ls_sp == -1, in_ls_sp+1 == 0 */
    if (size_t(in_ls_sp+1) < max_source_stack)
        in_ls_sp++;
    else
        throw overflow_error("linesourcestack overflow");
}

void haxpp_linesourcestack::pop() {
    /* in_ls_sp >= 0 should mean in_ls != NULL or else this code would not permit in_ls_sp >= 0 */
    if (in_ls_sp >= ssize_t(0))
        in_ls[in_ls_sp--].close();
    else
        throw underflow_error("linesourcestack underflow");
}

haxpp_linesource& haxpp_linesourcestack::top() {
    /* in_ls_sp >= 0 should mean in_ls != NULL or else this code would not permit in_ls_sp >= 0 */
    if (in_ls_sp >= ssize_t(0))
        return in_ls[in_ls_sp];

    throw underflow_error("linesourcestack attempt to read top() when empty");
}

const haxpp_linesource& haxpp_linesourcestack::top() const {
    /* in_ls_sp >= 0 should mean in_ls != NULL or else this code would not permit in_ls_sp >= 0 */
    if (in_ls_sp >= ssize_t(0))
        return in_ls[in_ls_sp];

    throw underflow_error("linesourcestack attempt to read top() when empty");
}

void haxpp_linesourcestack::clear() {
    while (!empty()) pop();
}

bool haxpp_linesourcestack::empty() const {
    /* in_ls_sp >= 0 should mean in_ls != NULL or else this code would not permit in_ls_sp >= 0 */
    return (in_ls_sp == ssize_t(-1));
}

static haxpp_linesourcestack    in_lstk;

static void help() {
    fprintf(stderr,"haxpp infile outfile\n");
}

static int parse_argv(int argc,char **argv) {
    int nwac=0;
    char *a;
    int i=1;

    while (i < argc) {
        a = argv[i++];

        if (*a == '-' && strcmp(a,"-") != 0/*not "-"*/) {
            do { a++; } while (*a == '-');

            if (!strcmp(a,"h") || !strcmp(a,"help")) {
                help();
                return 1;
            }
            else {
                fprintf(stderr,"Unknown switch %s\n",a);
                return 1;
            }
        }
        else {
            switch (nwac++) {
                case 0:
                    in_file = a;
                    break;
                case 1:
                    out_file = a;
                    break;
                default:
                    fprintf(stderr,"Unexpected arg %s\n",a);
                    return 1;
            }
        }
    }

    return 0;
}

void send_line(haxpp_linesink &ls,const string &name,const linecount_t line) {
    string msg = string("#line ") + to_string(line) + " \"" + name + "\"";
    ls.write(msg.c_str());
}

int main(int argc,char **argv) {
    if (parse_argv(argc,argv))
        return 1;

    in_lstk.push();
    if (in_file == "-")
        in_lstk.top().setsource(stdin);
    else
        in_lstk.top().setsource(in_file);

    if (!in_lstk.top().open()) {
        fprintf(stderr,"Unable to open infile, %s\n",strerror(errno));
        return 1;
    }

    if (out_file == "-")
        out_ls.setsink(stdout);
    else
        out_ls.setsink(out_file);

    if (!out_ls.open()) {
        fprintf(stderr,"Unable to open outfile, %s\n",strerror(errno));
        return 1;
    }
    send_line(out_ls,in_lstk.top().getsourcename(),1);

    while (!in_lstk.top().eof()) {
        char *line = in_lstk.top().readline();
        if (line == nullptr) {
            if (!in_lstk.top().error() && in_lstk.top().eof()) {
                in_lstk.pop();
                if (in_lstk.empty())
                    break;
                else
                    continue;
            }
            else {
                fprintf(stderr,"Problem reading. error=%u eof=%u errno=%s\n",in_lstk.top().error(),in_lstk.top().eof(),strerror(errno));
                return 1;
            }
        }

        if (!out_ls.write(line)) {
            fprintf(stderr,"Error writing output\n");
            return 1;
        }
    }

    if (!in_lstk.empty()) {
        if (in_lstk.top().error()) {
            fprintf(stderr,"An error occurred while parsing %s\n",in_lstk.top().getsourcename().c_str());
            return 1;
        }
    }

    if (out_ls.error()) {
        fprintf(stderr,"An error occurred while parsing %s\n",out_ls.getsinkname().c_str());
        return 1;
    }

    out_ls.close();
    in_lstk.clear();
    return 0;
}

<|endoftext|>


<commit_before>#include "cpp_redis/network/windows/io_service.hpp"
#include "cpp_redis/redis_error.hpp"

namespace cpp_redis {

namespace network {

const std::shared_ptr<io_service>&
io_service::get_instance(void) {
  static std::shared_ptr<io_service> instance = std::shared_ptr<io_service>{new io_service};
  return instance;
}

io_service::io_service(size_t max_worker_threads)
: m_should_stop(false) {
  //Determine the size of the thread pool dynamically.
  //2 * number of processors in the system is our rule here.
  SYSTEM_INFO info;
  ::GetSystemInfo(&info);
  m_worker_thread_pool_size = (info.dwNumberOfProcessors * 2);

  if (m_worker_thread_pool_size > max_worker_threads)
    m_worker_thread_pool_size = max_worker_threads;

  WSADATA wsaData;
  int nRet = 0;
  if ((nRet = WSAStartup(0x202, &wsaData)) != 0) //Start winsock before any other socket calls.
    throw cpp_redis::redis_error("Could not init cpp_redis::io_service, WSAStartup() failure");

  //Create completion port.  Pass 0 for parameter 4 to allow as many threads as there are processors in the system
  m_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
  ;
  if (INVALID_HANDLE_VALUE == m_completion_port)
    throw cpp_redis::redis_error("Could not init cpp_redis::io_service, CreateIoCompletionPort() failure");

  //Now startup worker thread pool which will service our async io requests
  for (unsigned int i = 0; i < m_worker_thread_pool_size; i++) {
    m_worker_threads.push_back(std::thread(&io_service::process_io, this));
  }
}

io_service::~io_service(void) {
  shutdown();
}

void
io_service::shutdown() {
  m_should_stop = true;

  //Iterate all of our sockets and shutdown any IO worker threads by posting a issuing a special
  //message to the thread to tell them to wake up and shut down.
  io_context_info* pInfo = NULL;

  auto sock_it = m_sockets.begin();
  while (sock_it != m_sockets.end()) {
    auto& info = sock_it->second;
    //Post for each of our worker threads.
    int workers = m_worker_threads.size();
    for (int i = 0; i < workers; i++)
      PostQueuedCompletionStatus(m_completion_port, 0, NULL, NULL); //Use NULL for the completion key to wake them up.
    sock_it++;
  }

  // Wait for the threads to finish
  for (auto& t : m_worker_threads)
    t.join();

  //close the completion port otherwise the worker threads will all be waiting on GetQueuedCompletionStatus()
  if (m_completion_port) {
    CloseHandle(m_completion_port);
    m_completion_port = NULL;
  }
}

//! add or remove a given socket from the io service
//! untrack should never be called from inside a callback
void
io_service::track(SOCKET sock, const disconnection_handler_t& handler) {
  std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);

  //Add the socket to our map and return the allocated struct
  auto& info = m_sockets[sock];

  info.hsock                 = sock;
  info.disconnection_handler = handler;

  //Associate the socket with our io completion port.
  if (NULL == CreateIoCompletionPort((HANDLE) sock, m_completion_port, (DWORD_PTR) &m_sockets[sock], 0)) {
    throw cpp_redis::redis_error("Track() failed to create CreateIoCompletionPort");
  }
}

void
io_service::untrack(SOCKET sock) {
  std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);
  m_sockets.erase(sock);
}

bool
io_service::async_read(SOCKET sock, std::vector<char>& buffer, std::size_t read_size, const read_callback_t& callback) {
  std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);

  auto sock_it = m_sockets.find(sock);
  if (sock_it == m_sockets.end())
    return false;

  //Resize the buffer to the correct size if we need it to be to hold the incoming data.
  if (buffer.size() < read_size)
    buffer.resize(read_size);

  auto& sockinfo         = sock_it->second;
  sockinfo.read_buffer   = &buffer;
  sockinfo.read_callback = callback;

  DWORD dwRecvNumBytes = 0;
  DWORD dwFlags        = 0;
  WSABUF buffRecv;

  buffRecv.buf = sockinfo.read_buffer->data();
  buffRecv.len = read_size;

  //We need a new overlapped struct for EACH overlapped operation.
  //we reuse them over and over.
  io_context_info* p_io_info = sockinfo.get_pool_io_context();

  int nRet = WSARecv(sock, &buffRecv, 1, &dwRecvNumBytes, &dwFlags, &(p_io_info->overlapped), NULL);

  if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())) {
    //Fire the disconnect handler
    sockinfo.disconnection_handler(*this);
    return false;
  }

  return true;
}

bool
io_service::async_write(SOCKET sock, const std::vector<char>& buffer, std::size_t write_size, const write_callback_t& callback) {
  std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);

  auto sock_it = m_sockets.find(sock);
  if (sock_it == m_sockets.end())
    return false;

  auto& sockinfo          = sock_it->second;
  sockinfo.write_buffer   = buffer;
  sockinfo.write_size     = write_size;
  sockinfo.write_callback = callback;

  WSABUF buffSend;
  DWORD dwSendNumBytes = 0;
  DWORD dwFlags        = 0;
  buffSend.buf         = sockinfo.write_buffer.data();
  buffSend.len         = write_size;

  //We need a new overlapped struct for EACH overlapped operation.
  //we reuse them over and over.
  io_context_info* p_io_info = sockinfo.get_pool_io_context();
  p_io_info->eOperation      = IO_OP_WRITE;

  int nRet = WSASend(sock, &buffSend, 1, &dwSendNumBytes, dwFlags, &(p_io_info->overlapped), NULL);
  if (SOCKET_ERROR == nRet) {
    int error = WSAGetLastError();
    if (error != ERROR_IO_PENDING) {
      //Fire the disconnect handler
      sockinfo.disconnection_handler(*this);
      return false;
    }
  }

  return true;
}

//function used by worker thread(s) used to process io requests
int
io_service::process_io(void) {
  BOOL bSuccess               = FALSE;
  int nRet                    = 0;
  LPWSAOVERLAPPED pOverlapped = NULL;
  sock_info* psock_info       = NULL;
  io_context_info* pio_info   = NULL;

  DWORD dwRecvNumBytes = 0;
  DWORD dwSendNumBytes = 0;
  DWORD dwFlags        = 0;
  DWORD io_size        = 0;
  enIoOperation e_op;
  int sock_error = 0;

  while (!m_should_stop) {
    // continually loop to service io completion packets
    psock_info  = NULL;
    pOverlapped = NULL;

    bSuccess = GetQueuedCompletionStatus(m_completion_port, &io_size, (PDWORD_PTR) &psock_info, (LPOVERLAPPED*) &pOverlapped, INFINITE);
    if (!bSuccess) {
      //client socket must have died. continue...
      if (0 == io_size) {
        sock_error = WSAGetLastError();
        //Fire the disconnect handler if we can.
        if (psock_info && sock_error != ERROR_CONNECTION_ABORTED) //Seems the psock_info structure is crap when ERROR_CONNECTION_ABORTED is captured.
          psock_info->disconnection_handler(*this);
        continue;
      }
      if (m_should_stop)
        return 0;
    }

    //get the base address of the struct holding lpOverlapped (the io_context_info) pointer.
    if (pOverlapped)
      pio_info = CONTAINING_RECORD(pOverlapped, io_context_info, overlapped);
    else
      pio_info = NULL;

    // Somebody used PostQueuedCompletionStatus to post an I/O packet with
    // a NULL CompletionKey (or if we get one for any reason).  It is time to exit.
    if (!psock_info || !pOverlapped)
      return 0;

    e_op = pio_info->eOperation;

    //Push it to the pool so another IO operation can use it again later
    if (pio_info)
      psock_info->return_pool_io_context(pio_info);
    pio_info = NULL;

    // First check to see if an error has occurred on the socket and if so
    // then close the socket and cleanup the SOCKET_INFORMATION structure associated with the socket
    if (0 == io_size) {
      //Fire the disconnect handler. Check if stopped first because of some weird timing issues that may get us here.
      if (bSuccess && false == m_should_stop && psock_info)
        psock_info->disconnection_handler(*this);
      continue;
    }

    // determine what type of IO packet has completed by checking the io_context_info
    // associated with this io operation. This will determine what action to take.
    switch (e_op) {
    case IO_OP_READ: // a read operation has completed
                     //TODO Resize Read buffer to the size that we read?
      {
        std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);
        if (m_sockets.find(psock_info->hsock) != m_sockets.end())
          psock_info->read_callback(io_size);
      }
      break;

    case IO_OP_WRITE: // a write operation has completed
      //Lock our socket structure before updating the write_size
      {
        std::lock_guard<std::recursive_mutex> socklock(psock_info->sock_info_mutex);
        psock_info->write_size -= io_size;
      }
      {
        std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);
        if (m_sockets.find(psock_info->hsock) != m_sockets.end())
          psock_info->write_callback(io_size);
      }
      break;
    } //switch
  }   //while

  return 0;
}

} //! network
} //! cpp_redis
<commit_msg>fix windows io_service: set the io_state to IO_OP_READ in async_read<commit_after>#include "cpp_redis/network/windows/io_service.hpp"
#include "cpp_redis/redis_error.hpp"

namespace cpp_redis {

namespace network {

const std::shared_ptr<io_service>&
io_service::get_instance(void) {
  static std::shared_ptr<io_service> instance = std::shared_ptr<io_service>{new io_service};
  return instance;
}

io_service::io_service(size_t max_worker_threads)
: m_should_stop(false) {
  //Determine the size of the thread pool dynamically.
  //2 * number of processors in the system is our rule here.
  SYSTEM_INFO info;
  ::GetSystemInfo(&info);
  m_worker_thread_pool_size = (info.dwNumberOfProcessors * 2);

  if (m_worker_thread_pool_size > max_worker_threads)
    m_worker_thread_pool_size = max_worker_threads;

  WSADATA wsaData;
  int nRet = 0;
  if ((nRet = WSAStartup(0x202, &wsaData)) != 0) //Start winsock before any other socket calls.
    throw cpp_redis::redis_error("Could not init cpp_redis::io_service, WSAStartup() failure");

  //Create completion port.  Pass 0 for parameter 4 to allow as many threads as there are processors in the system
  m_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
  ;
  if (INVALID_HANDLE_VALUE == m_completion_port)
    throw cpp_redis::redis_error("Could not init cpp_redis::io_service, CreateIoCompletionPort() failure");

  //Now startup worker thread pool which will service our async io requests
  for (unsigned int i = 0; i < m_worker_thread_pool_size; i++) {
    m_worker_threads.push_back(std::thread(&io_service::process_io, this));
  }
}

io_service::~io_service(void) {
  shutdown();
}

void
io_service::shutdown() {
  m_should_stop = true;

  //Iterate all of our sockets and shutdown any IO worker threads by posting a issuing a special
  //message to the thread to tell them to wake up and shut down.
  io_context_info* pInfo = NULL;

  auto sock_it = m_sockets.begin();
  while (sock_it != m_sockets.end()) {
    auto& info = sock_it->second;
    //Post for each of our worker threads.
    int workers = m_worker_threads.size();
    for (int i = 0; i < workers; i++)
      PostQueuedCompletionStatus(m_completion_port, 0, NULL, NULL); //Use NULL for the completion key to wake them up.
    sock_it++;
  }

  // Wait for the threads to finish
  for (auto& t : m_worker_threads)
    t.join();

  //close the completion port otherwise the worker threads will all be waiting on GetQueuedCompletionStatus()
  if (m_completion_port) {
    CloseHandle(m_completion_port);
    m_completion_port = NULL;
  }
}

//! add or remove a given socket from the io service
//! untrack should never be called from inside a callback
void
io_service::track(SOCKET sock, const disconnection_handler_t& handler) {
  std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);

  //Add the socket to our map and return the allocated struct
  auto& info = m_sockets[sock];

  info.hsock                 = sock;
  info.disconnection_handler = handler;

  //Associate the socket with our io completion port.
  if (NULL == CreateIoCompletionPort((HANDLE) sock, m_completion_port, (DWORD_PTR) &m_sockets[sock], 0)) {
    throw cpp_redis::redis_error("Track() failed to create CreateIoCompletionPort");
  }
}

void
io_service::untrack(SOCKET sock) {
  std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);
  m_sockets.erase(sock);
}

bool
io_service::async_read(SOCKET sock, std::vector<char>& buffer, std::size_t read_size, const read_callback_t& callback) {
  std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);

  auto sock_it = m_sockets.find(sock);
  if (sock_it == m_sockets.end())
    return false;

  //Resize the buffer to the correct size if we need it to be to hold the incoming data.
  if (buffer.size() < read_size)
    buffer.resize(read_size);

  auto& sockinfo         = sock_it->second;
  sockinfo.read_buffer   = &buffer;
  sockinfo.read_callback = callback;

  DWORD dwRecvNumBytes = 0;
  DWORD dwFlags        = 0;
  WSABUF buffRecv;

  buffRecv.buf = sockinfo.read_buffer->data();
  buffRecv.len = read_size;

  //We need a new overlapped struct for EACH overlapped operation.
  //we reuse them over and over.
  io_context_info* p_io_info = sockinfo.get_pool_io_context();
  p_io_info->eOperation = IO_OP_READ;

  int nRet = WSARecv(sock, &buffRecv, 1, &dwRecvNumBytes, &dwFlags, &(p_io_info->overlapped), NULL);

  if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())) {
    //Fire the disconnect handler
    sockinfo.disconnection_handler(*this);
    return false;
  }

  return true;
}

bool
io_service::async_write(SOCKET sock, const std::vector<char>& buffer, std::size_t write_size, const write_callback_t& callback) {
  std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);

  auto sock_it = m_sockets.find(sock);
  if (sock_it == m_sockets.end())
    return false;

  auto& sockinfo          = sock_it->second;
  sockinfo.write_buffer   = buffer;
  sockinfo.write_size     = write_size;
  sockinfo.write_callback = callback;

  WSABUF buffSend;
  DWORD dwSendNumBytes = 0;
  DWORD dwFlags        = 0;
  buffSend.buf         = sockinfo.write_buffer.data();
  buffSend.len         = write_size;

  //We need a new overlapped struct for EACH overlapped operation.
  //we reuse them over and over.
  io_context_info* p_io_info = sockinfo.get_pool_io_context();
  p_io_info->eOperation      = IO_OP_WRITE;

  int nRet = WSASend(sock, &buffSend, 1, &dwSendNumBytes, dwFlags, &(p_io_info->overlapped), NULL);
  if (SOCKET_ERROR == nRet) {
    int error = WSAGetLastError();
    if (error != ERROR_IO_PENDING) {
      //Fire the disconnect handler
      sockinfo.disconnection_handler(*this);
      return false;
    }
  }

  return true;
}

//function used by worker thread(s) used to process io requests
int
io_service::process_io(void) {
  BOOL bSuccess               = FALSE;
  int nRet                    = 0;
  LPWSAOVERLAPPED pOverlapped = NULL;
  sock_info* psock_info       = NULL;
  io_context_info* pio_info   = NULL;

  DWORD dwRecvNumBytes = 0;
  DWORD dwSendNumBytes = 0;
  DWORD dwFlags        = 0;
  DWORD io_size        = 0;
  enIoOperation e_op;
  int sock_error = 0;

  while (!m_should_stop) {
    // continually loop to service io completion packets
    psock_info  = NULL;
    pOverlapped = NULL;

    bSuccess = GetQueuedCompletionStatus(m_completion_port, &io_size, (PDWORD_PTR) &psock_info, (LPOVERLAPPED*) &pOverlapped, INFINITE);
    if (!bSuccess) {
      //client socket must have died. continue...
      if (0 == io_size) {
        sock_error = WSAGetLastError();
        //Fire the disconnect handler if we can.
        if (psock_info && sock_error != ERROR_CONNECTION_ABORTED) //Seems the psock_info structure is crap when ERROR_CONNECTION_ABORTED is captured.
          psock_info->disconnection_handler(*this);
        continue;
      }
      if (m_should_stop)
        return 0;
    }

    //get the base address of the struct holding lpOverlapped (the io_context_info) pointer.
    if (pOverlapped)
      pio_info = CONTAINING_RECORD(pOverlapped, io_context_info, overlapped);
    else
      pio_info = NULL;

    // Somebody used PostQueuedCompletionStatus to post an I/O packet with
    // a NULL CompletionKey (or if we get one for any reason).  It is time to exit.
    if (!psock_info || !pOverlapped)
      return 0;

    e_op = pio_info->eOperation;

    //Push it to the pool so another IO operation can use it again later
    if (pio_info)
      psock_info->return_pool_io_context(pio_info);
    pio_info = NULL;

    // First check to see if an error has occurred on the socket and if so
    // then close the socket and cleanup the SOCKET_INFORMATION structure associated with the socket
    if (0 == io_size) {
      //Fire the disconnect handler. Check if stopped first because of some weird timing issues that may get us here.
      if (bSuccess && false == m_should_stop && psock_info)
        psock_info->disconnection_handler(*this);
      continue;
    }

    // determine what type of IO packet has completed by checking the io_context_info
    // associated with this io operation. This will determine what action to take.
    switch (e_op) {
    case IO_OP_READ: // a read operation has completed
                     //TODO Resize Read buffer to the size that we read?
      {
        std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);
        if (m_sockets.find(psock_info->hsock) != m_sockets.end())
          psock_info->read_callback(io_size);
      }
      break;

    case IO_OP_WRITE: // a write operation has completed
      //Lock our socket structure before updating the write_size
      {
        std::lock_guard<std::recursive_mutex> socklock(psock_info->sock_info_mutex);
        psock_info->write_size -= io_size;
      }
      {
        std::lock_guard<std::recursive_mutex> lock(m_socket_mutex);
        if (m_sockets.find(psock_info->hsock) != m_sockets.end())
          psock_info->write_callback(io_size);
      }
      break;
    } //switch
  }   //while

  return 0;
}

} //! network
} //! cpp_redis
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: textsearch.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 09:38:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef INCLUDED_UNOTOOLSDLLAPI_H
#include "unotools/unotoolsdllapi.h"
#endif

#ifndef _UNOTOOLS_TEXTSEARCH_HXX
#define _UNOTOOLS_TEXTSEARCH_HXX

#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_
#include <com/sun/star/lang/Locale.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XTEXTSEARCH_HPP_
#include <com/sun/star/util/XTextSearch.hpp>
#endif

// Forward-Deklaration
class CharClass;

namespace com {
    namespace sun {
        namespace star {
            namespace util {
                struct SearchResult;
                struct SearchOptions;
            }
        }
    }
}

// ............................................................................
namespace utl
{
// ............................................................................

// SS - Klasse fuers Suchen
class UNOTOOLS_DLLPUBLIC SearchParam
{
public:
    enum SearchType{ SRCH_NORMAL, SRCH_REGEXP, SRCH_LEVDIST };

private:
    String sSrchStr;            // the search string
    String sReplaceStr;         // the replace string

    SearchType eSrchType;       // search normal/regular/LevDist

    int bWordOnly   : 1;        // used by normal search
    int bSrchInSel  : 1;        // search only in the selection
    int bCaseSense  : 1;        //

    // values for the "weight Levenshtein-Distance"
    int bLEV_Relaxed : 1;
    int nLEV_OtherX;
    int nLEV_ShorterY;
    int nLEV_LongerZ;

    // asian flags - used for the transliteration
    long nTransliterationFlags;

public:
    SearchParam( const String &rText,
                    SearchType eSrchType = SearchParam::SRCH_NORMAL,
                    BOOL bCaseSens = TRUE,
                    BOOL bWrdOnly = FALSE,
                    BOOL bSrchInSel = FALSE );
    SearchParam( const SearchParam& );

    const String&   GetSrchStr() const          { return sSrchStr; }
    const String&   GetReplaceStr() const       { return sReplaceStr; }
    SearchType      GetSrchType() const         { return eSrchType; }

    int             IsCaseSensitive() const     { return bCaseSense; }
    int             IsSrchInSelection() const   { return bSrchInSel; }
    int             IsSrchWordOnly() const      { return bWordOnly; }

    void SetSrchStr( const String& rStr )       { sSrchStr = rStr; }
    void SetReplaceStr( const String& rStr )    { sReplaceStr = rStr; }
    void SetSrchType( SearchType eType )        { eSrchType = eType; }

    void SetCaseSensitive( int bFlag )          { bCaseSense = bFlag; }
    void SetSrchInSelection( int bFlag )        { bSrchInSel = bFlag; }
    void SetSrchWordOnly( int bFlag )           { bWordOnly = bFlag; }

    int             IsSrchRelaxed() const       { return bLEV_Relaxed; }
    int             GetLEVOther() const         { return nLEV_OtherX; }
    int             GetLEVShorter() const       { return nLEV_ShorterY; }
    int             GetLEVLonger() const        { return nLEV_LongerZ; }

    void SetSrchRelaxed( int bFlag )            { bLEV_Relaxed = bFlag; }
    void SetLEVOther( int nValue )              { nLEV_OtherX = nValue; }
    void SetLEVShorter( int nValue )            { nLEV_ShorterY = nValue; }
    void SetLEVLonger( int nValue )             { nLEV_LongerZ = nValue; }

    long GetTransliterationFlags() const        { return nTransliterationFlags; }
    void SetTransliterationFlags( long nValue ) { nTransliterationFlags = nValue; }
};

//  Klasse zum Suchen eines Strings in einem String.
//  Unterstuetzt werden folgende Verfahren:
//      - normalen Text (Bayer/Moore)
//      - regulaere Ausdruecke
//      - gewichtete Levenshtein Distanz
//
//  Es kann Vorwaerts und Rueckwaerts gesucht werden!

class UNOTOOLS_DLLPUBLIC TextSearch
{
    com::sun::star::uno::Reference < com::sun::star::util::XTextSearch >
            xTextSearch;

    void Init( const SearchParam & rParam,
               const ::com::sun::star::lang::Locale& rLocale );

public:
    // rText ist der zusuchende String
    // this first two CTORs are deprecated!
    TextSearch( const SearchParam & rPara, ULONG nLanguage );
    TextSearch( const SearchParam & rPara, const CharClass& rCClass );

    TextSearch( const ::com::sun::star::util::SearchOptions& rPara );
    ~TextSearch();

    /* search in the (selected) text the search string:
        rScrTxt - the text, in in which we search
        pStart  - start position for the saerch
        pEnde   - end postion for the search

        RETURN values   ==  TRUE: something is found
                        - pStart start pos of the found text,
                        - pStart end pos of the found text,
                        - pSrchResult - the search reult with all found
                             positons. Is only filled with more positions
                             if the regular expression handles goups.

                        == FALSE: nothing found, pStart,pEnde unchanged.

        Definitions: start pos always inclusive, end pos always exclusive!
                     The position must always in the right direction!
                    search forward: start <= end
                    search backward: end <= start
    */
    int SearchFrwrd( const String &rStr,
                    xub_StrLen* pStart, xub_StrLen* pEnde,
                    ::com::sun::star::util::SearchResult* pSrchResult = 0 );
    int SearchBkwrd( const String &rStr,
                    xub_StrLen* pStart, xub_StrLen* pEnde,
                    ::com::sun::star::util::SearchResult* pSrchResult = 0 );

    void SetLocale( const ::com::sun::star::util::SearchOptions& rOpt,
                    const ::com::sun::star::lang::Locale& rLocale );
};

// ............................................................................
}   // namespace utl
// ............................................................................

#endif

<commit_msg>INTEGRATION: CWS warnings01 (1.7.16); FILE MERGED 2006/05/26 13:44:33 sb 1.7.16.3: #i53898# Made code warning-free and/or compile at all after resync to SRC680m170. 2006/05/12 16:27:46 sb 1.7.16.2: #i53898# Made code warning-free and/or compile at all after resync to SRC680m162 (and in some cases reverted previous, problematic changes). 2005/12/21 10:36:53 fs 1.7.16.1: #i55991# removed TextSearch ctor taking a ULONG-as-LanguageType parameter<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: textsearch.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 14:02:47 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef INCLUDED_UNOTOOLSDLLAPI_H
#include "unotools/unotoolsdllapi.h"
#endif

#ifndef _UNOTOOLS_TEXTSEARCH_HXX
#define _UNOTOOLS_TEXTSEARCH_HXX

#ifndef INCLUDED_I18NPOOL_LANG_H
#include <i18npool/lang.h>
#endif
#ifndef _STRING_HXX //autogen
#include <tools/string.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_
#include <com/sun/star/lang/Locale.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XTEXTSEARCH_HPP_
#include <com/sun/star/util/XTextSearch.hpp>
#endif

// Forward-Deklaration
class CharClass;

namespace com {
    namespace sun {
        namespace star {
            namespace util {
                struct SearchResult;
                struct SearchOptions;
            }
        }
    }
}

// ............................................................................
namespace utl
{
// ............................................................................

// SS - Klasse fuers Suchen
class UNOTOOLS_DLLPUBLIC SearchParam
{
public:
    enum SearchType{ SRCH_NORMAL, SRCH_REGEXP, SRCH_LEVDIST };

private:
    String sSrchStr;            // the search string
    String sReplaceStr;         // the replace string

    SearchType eSrchType;       // search normal/regular/LevDist

    int bWordOnly   : 1;        // used by normal search
    int bSrchInSel  : 1;        // search only in the selection
    int bCaseSense  : 1;        //

    // values for the "weight Levenshtein-Distance"
    int bLEV_Relaxed : 1;
    int nLEV_OtherX;
    int nLEV_ShorterY;
    int nLEV_LongerZ;

    // asian flags - used for the transliteration
    long nTransliterationFlags;

public:
    SearchParam( const String &rText,
                    SearchType eSrchType = SearchParam::SRCH_NORMAL,
                    BOOL bCaseSens = TRUE,
                    BOOL bWrdOnly = FALSE,
                    BOOL bSrchInSel = FALSE );
    SearchParam( const SearchParam& );

    const String&   GetSrchStr() const          { return sSrchStr; }
    const String&   GetReplaceStr() const       { return sReplaceStr; }
    SearchType      GetSrchType() const         { return eSrchType; }

    int             IsCaseSensitive() const     { return bCaseSense; }
    int             IsSrchInSelection() const   { return bSrchInSel; }
    int             IsSrchWordOnly() const      { return bWordOnly; }

    void SetSrchStr( const String& rStr )       { sSrchStr = rStr; }
    void SetReplaceStr( const String& rStr )    { sReplaceStr = rStr; }
    void SetSrchType( SearchType eType )        { eSrchType = eType; }

    void SetCaseSensitive( int bFlag )          { bCaseSense = bFlag; }
    void SetSrchInSelection( int bFlag )        { bSrchInSel = bFlag; }
    void SetSrchWordOnly( int bFlag )           { bWordOnly = bFlag; }

    int             IsSrchRelaxed() const       { return bLEV_Relaxed; }
    int             GetLEVOther() const         { return nLEV_OtherX; }
    int             GetLEVShorter() const       { return nLEV_ShorterY; }
    int             GetLEVLonger() const        { return nLEV_LongerZ; }

    void SetSrchRelaxed( int bFlag )            { bLEV_Relaxed = bFlag; }
    void SetLEVOther( int nValue )              { nLEV_OtherX = nValue; }
    void SetLEVShorter( int nValue )            { nLEV_ShorterY = nValue; }
    void SetLEVLonger( int nValue )             { nLEV_LongerZ = nValue; }

    long GetTransliterationFlags() const        { return nTransliterationFlags; }
    void SetTransliterationFlags( long nValue ) { nTransliterationFlags = nValue; }
};

//  Klasse zum Suchen eines Strings in einem String.
//  Unterstuetzt werden folgende Verfahren:
//      - normalen Text (Bayer/Moore)
//      - regulaere Ausdruecke
//      - gewichtete Levenshtein Distanz
//
//  Es kann Vorwaerts und Rueckwaerts gesucht werden!

class UNOTOOLS_DLLPUBLIC TextSearch
{
    com::sun::star::uno::Reference < com::sun::star::util::XTextSearch >
            xTextSearch;

    void Init( const SearchParam & rParam,
               const ::com::sun::star::lang::Locale& rLocale );

public:
    // rText ist der zusuchende String
    // this first two CTORs are deprecated!
    TextSearch( const SearchParam & rPara, LanguageType nLanguage );
    TextSearch( const SearchParam & rPara, const CharClass& rCClass );

    TextSearch( const ::com::sun::star::util::SearchOptions& rPara );
    ~TextSearch();

    /* search in the (selected) text the search string:
        rScrTxt - the text, in in which we search
        pStart  - start position for the saerch
        pEnde   - end postion for the search

        RETURN values   ==  TRUE: something is found
                        - pStart start pos of the found text,
                        - pStart end pos of the found text,
                        - pSrchResult - the search reult with all found
                             positons. Is only filled with more positions
                             if the regular expression handles goups.

                        == FALSE: nothing found, pStart,pEnde unchanged.

        Definitions: start pos always inclusive, end pos always exclusive!
                     The position must always in the right direction!
                    search forward: start <= end
                    search backward: end <= start
    */
    int SearchFrwrd( const String &rStr,
                    xub_StrLen* pStart, xub_StrLen* pEnde,
                    ::com::sun::star::util::SearchResult* pSrchResult = 0 );
    int SearchBkwrd( const String &rStr,
                    xub_StrLen* pStart, xub_StrLen* pEnde,
                    ::com::sun::star::util::SearchResult* pSrchResult = 0 );

    void SetLocale( const ::com::sun::star::util::SearchOptions& rOpt,
                    const ::com::sun::star::lang::Locale& rLocale );
};

// ............................................................................
}   // namespace utl
// ............................................................................

#endif

<|endoftext|>


<commit_before>//=======================================================================
// Copyright 2014-2015 David Simmons-Duffin.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <vector>
#include "Matrix.h"

#include "Timers.h"

// Most of the routines below are helpfully-named wrappers for
// functions in MBLAS or MLAPACK.  See Matrix.h for a more detailed
// description of the various input/output parameters.
//
// For a list of MBLAS routines with documentation, see
// http://mplapack.sourceforge.net/mblas_routines.html
//
// For a list of MLAPACK routines with documentation, see
// http://mplapack.sourceforge.net/mlapack_routines.html
//
// We have chosen not to parallelize operations that are used in
// BlockDiagonalMatrix, since there parallelism can be achieved by
// parallelizing loops over blocks.

mpf_class * randomGMPVector2(int size, int prec) {
    gmp_randclass rr(gmp_randinit_default);
    rr.seed(time(NULL));

    //mpf_class * tmp = static_cast<mpf_class*> ( malloc(size * sizeof(mpf_class)) );

    auto tmp = new mpf_class [size];

    for (int i = 0; i < size; i++) {
        //new(tmp+i) mpf_class("0",prec);
        tmp[i].set_prec(prec);
	//mpz_class z = rr.get_z_range(200);
	tmp[i] = 10*rr.get_f(prec)-5;
        //mpf_pow_ui(tmp[i].get_mpf_t(),tmp[i].get_mpf_t(), z.get_ui());

    }

    return tmp;
    }

ostream& operator<<(ostream& os, const Matrix& a) {
  os << "{";
  for (int r = 0; r < a.rows; r++) {
    os << "{";
    for (int c = 0; c < a.cols; c++) {
      os << a.elt(r, c);
      if (c < a.cols-1)
        os << ", ";
    }
    os << "}";
    if (r < a.rows-1)
      os << ", ";
  }
  os << "}";
  return os;
}

// C := alpha*A*B + beta*C
void matrixScaleMultiplyAdd(Real alpha, Matrix &A, Matrix &B,
                            Real beta, Matrix &C) {
  assert(A.cols == B.rows);
  assert(A.rows == C.rows);
  assert(B.cols == C.cols);

  Rgemm("N", "N", A.rows, B.cols, A.cols, alpha,
        &A.elements[0], A.rows,
        &B.elements[0], B.rows,
        beta,
        &C.elements[0], C.rows);
}

// C := A*B
void matrixMultiply(Matrix &A, Matrix &B, Matrix &C) {
  matrixScaleMultiplyAdd(1, A, B, 0, C);
}

// Set block starting at (bRow, bCol) of B to A^T A
void matrixSquareIntoBlock(Matrix &A, Matrix &B, int bRow, int bCol) {
  assert(bRow + A.cols <= B.rows);
  assert(bCol + A.cols <= B.cols);

  // This operation is not used within a BlockDiagonalMatrix, so it is
  // worthwhile to parallelize.  In fact, this function, used in
  // computing TopLeft(Q) = SchurOffDiagonal^T SchurOffDiagonal (see
  // SDPSolver.cpp) is one of the main performance bottlenecks in the
  // solver.

  #pragma omp parallel for schedule(dynamic)
  for (int c = 0; c < A.cols; c++) {
    for (int r = 0; r <= c; r++) {
      Real tmp = 0;
      for (int p = 0; p < A.rows; p++)
        tmp += A.elt(p, r) * A.elt(p, c);
      B.elt(bRow + r, bCol + c) = tmp;
      if (r != c)
        B.elt(bRow + c, bCol + r) = tmp;
    }
  }
}

// Set block starting at (bRow, bCol) of B to A^T A
#ifdef __SDPB_CUDA__
  void matrixSquareIntoBlockMpmat(mpmat &myWorkspace, Matrix &A, Matrix &B, int bRow, int bCol, bool gpu){
#else
  void matrixSquareIntoBlockMpmat(mpmat &myWorkspace, Matrix &A, Matrix &B, int bRow, int bCol){
#endif
  assert(bRow + A.cols <= B.rows);
  assert(bCol + A.cols <= B.cols);

  // This operation is not used within a BlockDiagonalMatrix, so it is
  // worthwhile to parallelize.  In fact, this function, used in
  // computing TopLeft(Q) = SchurOffDiagonal^T SchurOffDiagonal (see
  // SDPSolver.cpp) is one of the main performance bottlenecks in the
  // solver.

  timers["matrixSquareIntoBlockMpmat.complete"].resume();

  mpf_set_default_prec(mpf_get_default_prec()+256);
  Real * block = new Real[A.cols*A.cols];

  mpf_set_default_prec(mpf_get_default_prec()-256);

  for (int c = 0; c < A.cols; ++c){
    for (int r = 0; r < A.cols; ++r){
      block[r*A.cols+c] = B.elt(bRow + r, bCol + c);
    }
   }

#ifdef __SDPB_CUDA__
  if (gpu)
    myWorkspace.syrk_reduced_gpu(CblasRowMajor,CblasTrans,A.cols,A.rows,A.elements.data(),block);
  else
    myWorkspace.syrk_reduced(CblasRowMajor,CblasTrans,A.cols,A.rows,A.elements.data(),block);
#else
  myWorkspace.syrk_reduced(CblasRowMajor,CblasTrans,A.cols,A.rows,A.elements.data(),block);
#endif

  for (int c = 0; c < A.cols; ++c){
    for (int r = 0; r < A.cols; ++r){
    B.elt(bRow + r, bCol + c) = block[r*A.cols+c];
}
}

  delete [] block;

  timers["matrixSquareIntoBlockMpmat.complete"].stop();

}

// A := L^{-1} A L^{-T}
void lowerTriangularInverseCongruence(Matrix &A, Matrix &L) {
  int dim = A.rows;
  assert(A.cols == dim);
  assert(L.rows == dim);
  assert(L.cols == dim);

  // A := A L^{-T}
  Rtrsm("Right", "Lower", "Transpose", "NonUnitDiagonal", dim, dim, 1,
        &L.elements[0], dim,
        &A.elements[0], dim);

  // A := L^{-1} A
  Rtrsm("Left", "Lower", "NoTranspose", "NonUnitDiagonal", dim, dim, 1,
        &L.elements[0], dim,
        &A.elements[0], dim);
}

// y := alpha A x + beta y
void vectorScaleMatrixMultiplyAdd(Real alpha, Matrix &A, Vector &x,
                                  Real beta, Vector &y) {
  assert(A.cols <= static_cast<int>(x.size()));
  assert(A.rows <= static_cast<int>(y.size()));

  #pragma omp parallel for schedule(static)
  for (int p = 0; p < A.rows; p++) {
    Real tmp = 0;
    for (int n = 0; n < A.cols; n++)
      tmp += A.elt(p, n)*x[n];
    y[p] = alpha*tmp + beta*y[p];
  }
}

// y := alpha A^T x + beta y
void vectorScaleMatrixMultiplyTransposeAdd(Real alpha, Matrix &A, Vector &x,
                                           Real beta, Vector &y) {
  assert(A.cols <= static_cast<int>(y.size()));
  assert(A.rows <= static_cast<int>(x.size()));

  #pragma omp parallel for schedule(static)
  for (int n = 0; n < A.cols; n++) {
    Real tmp = 0;
    for (int p = 0; p < A.rows; p++)
      tmp += A.elt(p, n)*x[p];
    y[n] = alpha*tmp + beta*y[n];
  }
}

// Tr(A B), where A and B are symmetric
Real frobeniusProductSymmetric(const Matrix &A, const Matrix &B) {
  assert(A.rows == B.rows);
  assert(A.cols == B.cols);
  assert(A.rows == A.cols);

  Real result = 0;
  for (int c = 0; c < A.cols; c++)
    for (int r = 0; r < c ; r++)
      result += A.elt(r, c)*B.elt(r, c);
  result *= 2;

  for (int r = 0; r < A.rows; r++)
    result += A.elt(r, r)*B.elt(r, r);

  return result;
}

// (X + dX) . (Y + dY), where X, dX, Y, dY are symmetric Matrices and
// '.' is the Frobenius product.
//
Real frobeniusProductOfSums(const Matrix &X, const Matrix &dX,
                            const Matrix &Y, const Matrix &dY) {
  Real result = 0;

  for (int c = 0; c < X.cols; c++)
    for (int r = 0; r < c; r++)
      result += (X.elt(r, c) + dX.elt(r, c)) * (Y.elt(r, c) + dY.elt(r, c));
  result *= 2;

  for (int r = 0; r < X.rows; r++)
    result += (X.elt(r, r) + dX.elt(r, r)) * (Y.elt(r, r) + dY.elt(r, r));

  return result;
}

// Compute the eigenvalues of A, via the QR method
void matrixEigenvalues(Matrix &A, Vector &workspace, Vector &eigenvalues) {
  assert(A.rows == A.cols);
  assert(static_cast<int>(eigenvalues.size()) == A.rows);
  assert(static_cast<int>(workspace.size()) == 3*A.rows - 1);

  Integer info;
  Integer workSize = workspace.size();
  Rsyev("NoEigenvectors", "LowerTriangular", A.rows, &A.elements[0],
        A.rows, &eigenvalues[0], &workspace[0], workSize, &info);
  assert(info == 0);
}

// Minimum eigenvalue of A, via the QR method
Real minEigenvalue(Matrix &A, Vector &workspace, Vector &eigenvalues) {
  matrixEigenvalues(A, workspace, eigenvalues);
  return eigenvalues[0];
}

// Compute an in-place LU decomposition of A, with pivots, suitable
// for use with 'solveWithLUDecomposition'
void LUDecomposition(Matrix &A, vector<Integer> &pivots) {
  int dim = A.rows;
  assert(A.cols == dim);

  Integer info;
  Rgetrf(dim, dim, &A.elements[0], dim, &pivots[0], &info);
  assert(info == 0);
}

// b := A^{-1} b, where LU and pivots encode the LU decomposition of A
void solveWithLUDecomposition(Matrix &LU, vector<Integer> &pivots, Vector &b) {
  Integer info;
  Rgetrs("NoTranspose", LU.rows, 1, &LU.elements[0], LU.rows,
         &pivots[0], &b[0], b.size(), &info);
  assert(info == 0);
}

// L (lower triangular) such that A = L L^T
void choleskyDecomposition(Matrix &A, Matrix &L) {
  int dim = A.rows;
  assert(A.cols == dim);
  assert(L.rows == dim);
  assert(L.cols == dim);

  // Set lower-triangular part of L to cholesky decomposition
  L.copyFrom(A);
  Integer info;
  Rpotrf("Lower", dim, &L.elements[0], dim, &info);
  assert(info == 0);

  // Set the upper-triangular part of the L to zero
  for (int j = 0; j < dim; j++)
    for (int i = 0; i < j; i++)
      L.elements[i + j*dim] = 0;
}

// Compute L (lower triangular) such that A + U U^T = L L^T.
void choleskyDecompositionStabilized(Matrix &A, Matrix &L,
                                     vector<Integer> &stabilizeIndices,
                                     vector<Real> &stabilizeLambdas,
                                     const double stabilizeThreshold) {
  int dim = A.rows;
  assert(A.cols == dim);
  assert(L.rows == dim);
  assert(L.cols == dim);

  // Set lower-triangular part of L to cholesky decomposition
  L.copyFrom(A);
  Integer info;
  RpotrfStabilized("Lower", dim, &L.elements[0], dim, &info,
                   stabilizeIndices, stabilizeLambdas, stabilizeThreshold);
  assert(info == 0);

  // Set the upper-triangular part of the L to zero
  for (int j = 0; j < dim; j++)
    for (int i = 0; i < j; i++)
      L.elements[i + j*dim] = 0;
}

// B := L^{-1} B, where L is lower-triangular and B is a matrix
// pointed to by b
void lowerTriangularSolve(Matrix &L, Real *b, int bcols, int ldb) {
  int dim = L.rows;
  assert(L.cols == dim);

  Rtrsm("Left", "Lower", "NoTranspose", "NonUnitDiagonal",
        dim, bcols, 1, &L.elements[0], dim, b, ldb);
}

// b := L^{-1} b, where L is lower-triangular
void lowerTriangularSolve(Matrix &L, Vector &b) {
  assert(static_cast<int>(b.size()) == L.rows);
  lowerTriangularSolve(L, &b[0], 1, b.size());
}

// B := L^{-T} B, where L is lower-triangular and B is a matrix
// pointed to by b
void lowerTriangularTransposeSolve(Matrix &L, Real *b, int bcols, int ldb) {
  int dim = L.rows;
  assert(L.cols == dim);

  Rtrsm("Left", "Lower", "Transpose", "NonUnitDiagonal",
        dim, bcols, 1, &L.elements[0], dim, b, ldb);
}

// b := L^{-T} b, where L is lower-triangular
void lowerTriangularTransposeSolve(Matrix &L, Vector &b) {
  assert(static_cast<int>(b.size()) == L.rows);
  lowerTriangularTransposeSolve(L, &b[0], 1, b.size());
}

// X := ACholesky^{-1 T} ACholesky^{-1} X = A^{-1} X
void matrixSolveWithCholesky(Matrix &ACholesky, Matrix &X) {
  int dim = X.rows;
  assert(X.cols == dim);
  assert(ACholesky.rows == dim);
  assert(ACholesky.cols == dim);

  lowerTriangularSolve(ACholesky, &X.elements[0], X.cols, X.rows);
  lowerTriangularTransposeSolve(ACholesky, &X.elements[0], X.cols, X.rows);
}
<commit_msg>deleted some junk<commit_after>//=======================================================================
// Copyright 2014-2015 David Simmons-Duffin.
// Distributed under the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <vector>
#include "Matrix.h"

#include "Timers.h"

// Most of the routines below are helpfully-named wrappers for
// functions in MBLAS or MLAPACK.  See Matrix.h for a more detailed
// description of the various input/output parameters.
//
// For a list of MBLAS routines with documentation, see
// http://mplapack.sourceforge.net/mblas_routines.html
//
// For a list of MLAPACK routines with documentation, see
// http://mplapack.sourceforge.net/mlapack_routines.html
//
// We have chosen not to parallelize operations that are used in
// BlockDiagonalMatrix, since there parallelism can be achieved by
// parallelizing loops over blocks.

ostream& operator<<(ostream& os, const Matrix& a) {
  os << "{";
  for (int r = 0; r < a.rows; r++) {
    os << "{";
    for (int c = 0; c < a.cols; c++) {
      os << a.elt(r, c);
      if (c < a.cols-1)
        os << ", ";
    }
    os << "}";
    if (r < a.rows-1)
      os << ", ";
  }
  os << "}";
  return os;
}

// C := alpha*A*B + beta*C
void matrixScaleMultiplyAdd(Real alpha, Matrix &A, Matrix &B,
                            Real beta, Matrix &C) {
  assert(A.cols == B.rows);
  assert(A.rows == C.rows);
  assert(B.cols == C.cols);

  Rgemm("N", "N", A.rows, B.cols, A.cols, alpha,
        &A.elements[0], A.rows,
        &B.elements[0], B.rows,
        beta,
        &C.elements[0], C.rows);
}

// C := A*B
void matrixMultiply(Matrix &A, Matrix &B, Matrix &C) {
  matrixScaleMultiplyAdd(1, A, B, 0, C);
}

// Set block starting at (bRow, bCol) of B to A^T A
void matrixSquareIntoBlock(Matrix &A, Matrix &B, int bRow, int bCol) {
  assert(bRow + A.cols <= B.rows);
  assert(bCol + A.cols <= B.cols);

  // This operation is not used within a BlockDiagonalMatrix, so it is
  // worthwhile to parallelize.  In fact, this function, used in
  // computing TopLeft(Q) = SchurOffDiagonal^T SchurOffDiagonal (see
  // SDPSolver.cpp) is one of the main performance bottlenecks in the
  // solver.

  #pragma omp parallel for schedule(dynamic)
  for (int c = 0; c < A.cols; c++) {
    for (int r = 0; r <= c; r++) {
      Real tmp = 0;
      for (int p = 0; p < A.rows; p++)
        tmp += A.elt(p, r) * A.elt(p, c);
      B.elt(bRow + r, bCol + c) = tmp;
      if (r != c)
        B.elt(bRow + c, bCol + r) = tmp;
    }
  }
}

// Set block starting at (bRow, bCol) of B to A^T A
#ifdef __SDPB_CUDA__
  void matrixSquareIntoBlockMpmat(mpmat &myWorkspace, Matrix &A, Matrix &B, int bRow, int bCol, bool gpu){
#else
  void matrixSquareIntoBlockMpmat(mpmat &myWorkspace, Matrix &A, Matrix &B, int bRow, int bCol){
#endif
  assert(bRow + A.cols <= B.rows);
  assert(bCol + A.cols <= B.cols);

  // This operation is not used within a BlockDiagonalMatrix, so it is
  // worthwhile to parallelize.  In fact, this function, used in
  // computing TopLeft(Q) = SchurOffDiagonal^T SchurOffDiagonal (see
  // SDPSolver.cpp) is one of the main performance bottlenecks in the
  // solver.

  timers["matrixSquareIntoBlockMpmat.complete"].resume();

  mpf_set_default_prec(mpf_get_default_prec()+256);
  Real * block = new Real[A.cols*A.cols];

  mpf_set_default_prec(mpf_get_default_prec()-256);

  for (int c = 0; c < A.cols; ++c){
    for (int r = 0; r < A.cols; ++r){
      block[r*A.cols+c] = B.elt(bRow + r, bCol + c);
    }
   }

#ifdef __SDPB_CUDA__
  if (gpu)
    myWorkspace.syrk_reduced_gpu(CblasRowMajor,CblasTrans,A.cols,A.rows,A.elements.data(),block);
  else
    myWorkspace.syrk_reduced(CblasRowMajor,CblasTrans,A.cols,A.rows,A.elements.data(),block);
#else
  myWorkspace.syrk_reduced(CblasRowMajor,CblasTrans,A.cols,A.rows,A.elements.data(),block);
#endif

  for (int c = 0; c < A.cols; ++c){
    for (int r = 0; r < A.cols; ++r){
    B.elt(bRow + r, bCol + c) = block[r*A.cols+c];
}
}

  delete [] block;

  timers["matrixSquareIntoBlockMpmat.complete"].stop();

}

// A := L^{-1} A L^{-T}
void lowerTriangularInverseCongruence(Matrix &A, Matrix &L) {
  int dim = A.rows;
  assert(A.cols == dim);
  assert(L.rows == dim);
  assert(L.cols == dim);

  // A := A L^{-T}
  Rtrsm("Right", "Lower", "Transpose", "NonUnitDiagonal", dim, dim, 1,
        &L.elements[0], dim,
        &A.elements[0], dim);

  // A := L^{-1} A
  Rtrsm("Left", "Lower", "NoTranspose", "NonUnitDiagonal", dim, dim, 1,
        &L.elements[0], dim,
        &A.elements[0], dim);
}

// y := alpha A x + beta y
void vectorScaleMatrixMultiplyAdd(Real alpha, Matrix &A, Vector &x,
                                  Real beta, Vector &y) {
  assert(A.cols <= static_cast<int>(x.size()));
  assert(A.rows <= static_cast<int>(y.size()));

  #pragma omp parallel for schedule(static)
  for (int p = 0; p < A.rows; p++) {
    Real tmp = 0;
    for (int n = 0; n < A.cols; n++)
      tmp += A.elt(p, n)*x[n];
    y[p] = alpha*tmp + beta*y[p];
  }
}

// y := alpha A^T x + beta y
void vectorScaleMatrixMultiplyTransposeAdd(Real alpha, Matrix &A, Vector &x,
                                           Real beta, Vector &y) {
  assert(A.cols <= static_cast<int>(y.size()));
  assert(A.rows <= static_cast<int>(x.size()));

  #pragma omp parallel for schedule(static)
  for (int n = 0; n < A.cols; n++) {
    Real tmp = 0;
    for (int p = 0; p < A.rows; p++)
      tmp += A.elt(p, n)*x[p];
    y[n] = alpha*tmp + beta*y[n];
  }
}

// Tr(A B), where A and B are symmetric
Real frobeniusProductSymmetric(const Matrix &A, const Matrix &B) {
  assert(A.rows == B.rows);
  assert(A.cols == B.cols);
  assert(A.rows == A.cols);

  Real result = 0;
  for (int c = 0; c < A.cols; c++)
    for (int r = 0; r < c ; r++)
      result += A.elt(r, c)*B.elt(r, c);
  result *= 2;

  for (int r = 0; r < A.rows; r++)
    result += A.elt(r, r)*B.elt(r, r);

  return result;
}

// (X + dX) . (Y + dY), where X, dX, Y, dY are symmetric Matrices and
// '.' is the Frobenius product.
//
Real frobeniusProductOfSums(const Matrix &X, const Matrix &dX,
                            const Matrix &Y, const Matrix &dY) {
  Real result = 0;

  for (int c = 0; c < X.cols; c++)
    for (int r = 0; r < c; r++)
      result += (X.elt(r, c) + dX.elt(r, c)) * (Y.elt(r, c) + dY.elt(r, c));
  result *= 2;

  for (int r = 0; r < X.rows; r++)
    result += (X.elt(r, r) + dX.elt(r, r)) * (Y.elt(r, r) + dY.elt(r, r));

  return result;
}

// Compute the eigenvalues of A, via the QR method
void matrixEigenvalues(Matrix &A, Vector &workspace, Vector &eigenvalues) {
  assert(A.rows == A.cols);
  assert(static_cast<int>(eigenvalues.size()) == A.rows);
  assert(static_cast<int>(workspace.size()) == 3*A.rows - 1);

  Integer info;
  Integer workSize = workspace.size();
  Rsyev("NoEigenvectors", "LowerTriangular", A.rows, &A.elements[0],
        A.rows, &eigenvalues[0], &workspace[0], workSize, &info);
  assert(info == 0);
}

// Minimum eigenvalue of A, via the QR method
Real minEigenvalue(Matrix &A, Vector &workspace, Vector &eigenvalues) {
  matrixEigenvalues(A, workspace, eigenvalues);
  return eigenvalues[0];
}

// Compute an in-place LU decomposition of A, with pivots, suitable
// for use with 'solveWithLUDecomposition'
void LUDecomposition(Matrix &A, vector<Integer> &pivots) {
  int dim = A.rows;
  assert(A.cols == dim);

  Integer info;
  Rgetrf(dim, dim, &A.elements[0], dim, &pivots[0], &info);
  assert(info == 0);
}

// b := A^{-1} b, where LU and pivots encode the LU decomposition of A
void solveWithLUDecomposition(Matrix &LU, vector<Integer> &pivots, Vector &b) {
  Integer info;
  Rgetrs("NoTranspose", LU.rows, 1, &LU.elements[0], LU.rows,
         &pivots[0], &b[0], b.size(), &info);
  assert(info == 0);
}

// L (lower triangular) such that A = L L^T
void choleskyDecomposition(Matrix &A, Matrix &L) {
  int dim = A.rows;
  assert(A.cols == dim);
  assert(L.rows == dim);
  assert(L.cols == dim);

  // Set lower-triangular part of L to cholesky decomposition
  L.copyFrom(A);
  Integer info;
  Rpotrf("Lower", dim, &L.elements[0], dim, &info);
  assert(info == 0);

  // Set the upper-triangular part of the L to zero
  for (int j = 0; j < dim; j++)
    for (int i = 0; i < j; i++)
      L.elements[i + j*dim] = 0;
}

// Compute L (lower triangular) such that A + U U^T = L L^T.
void choleskyDecompositionStabilized(Matrix &A, Matrix &L,
                                     vector<Integer> &stabilizeIndices,
                                     vector<Real> &stabilizeLambdas,
                                     const double stabilizeThreshold) {
  int dim = A.rows;
  assert(A.cols == dim);
  assert(L.rows == dim);
  assert(L.cols == dim);

  // Set lower-triangular part of L to cholesky decomposition
  L.copyFrom(A);
  Integer info;
  RpotrfStabilized("Lower", dim, &L.elements[0], dim, &info,
                   stabilizeIndices, stabilizeLambdas, stabilizeThreshold);
  assert(info == 0);

  // Set the upper-triangular part of the L to zero
  for (int j = 0; j < dim; j++)
    for (int i = 0; i < j; i++)
      L.elements[i + j*dim] = 0;
}

// B := L^{-1} B, where L is lower-triangular and B is a matrix
// pointed to by b
void lowerTriangularSolve(Matrix &L, Real *b, int bcols, int ldb) {
  int dim = L.rows;
  assert(L.cols == dim);

  Rtrsm("Left", "Lower", "NoTranspose", "NonUnitDiagonal",
        dim, bcols, 1, &L.elements[0], dim, b, ldb);
}

// b := L^{-1} b, where L is lower-triangular
void lowerTriangularSolve(Matrix &L, Vector &b) {
  assert(static_cast<int>(b.size()) == L.rows);
  lowerTriangularSolve(L, &b[0], 1, b.size());
}

// B := L^{-T} B, where L is lower-triangular and B is a matrix
// pointed to by b
void lowerTriangularTransposeSolve(Matrix &L, Real *b, int bcols, int ldb) {
  int dim = L.rows;
  assert(L.cols == dim);

  Rtrsm("Left", "Lower", "Transpose", "NonUnitDiagonal",
        dim, bcols, 1, &L.elements[0], dim, b, ldb);
}

// b := L^{-T} b, where L is lower-triangular
void lowerTriangularTransposeSolve(Matrix &L, Vector &b) {
  assert(static_cast<int>(b.size()) == L.rows);
  lowerTriangularTransposeSolve(L, &b[0], 1, b.size());
}

// X := ACholesky^{-1 T} ACholesky^{-1} X = A^{-1} X
void matrixSolveWithCholesky(Matrix &ACholesky, Matrix &X) {
  int dim = X.rows;
  assert(X.cols == dim);
  assert(ACholesky.rows == dim);
  assert(ACholesky.cols == dim);

  lowerTriangularSolve(ACholesky, &X.elements[0], X.cols, X.rows);
  lowerTriangularTransposeSolve(ACholesky, &X.elements[0], X.cols, X.rows);
}
<|endoftext|>