<commit_before>//===- X86LegalizerInfo.cpp --------------------------------------*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the targeting of the Machinelegalizer class for X86.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

#include "X86LegalizerInfo.h"
#include "X86Subtarget.h"
#include "X86TargetMachine.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"
#include "llvm/Target/TargetOpcodes.h"

using namespace llvm;
using namespace TargetOpcode;

X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
                                   const X86TargetMachine &TM)
    : Subtarget(STI), TM(TM) {

  setLegalizerInfo32bit();
  setLegalizerInfo64bit();
  setLegalizerInfoSSE1();
  setLegalizerInfoSSE2();
  setLegalizerInfoSSE41();
  setLegalizerInfoAVX();
  setLegalizerInfoAVX2();
  setLegalizerInfoAVX512();
  setLegalizerInfoAVX512DQ();
  setLegalizerInfoAVX512BW();

  computeTables();
}

void X86LegalizerInfo::setLegalizerInfo32bit() {

  if (Subtarget.is64Bit())
    return;

  const LLT p0 = LLT::pointer(0, 32);
  const LLT s1 = LLT::scalar(1);
  const LLT s8 = LLT::scalar(8);
  const LLT s16 = LLT::scalar(16);
  const LLT s32 = LLT::scalar(32);
  const LLT s64 = LLT::scalar(64);

  for (auto Ty : {p0, s1, s8, s16, s32})
    setAction({G_IMPLICIT_DEF, Ty}, Legal);

  for (unsigned BinOp : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR})
    for (auto Ty : {s8, s16, s32})
      setAction({BinOp, Ty}, Legal);

  for (unsigned Op : {G_UADDE}) {
    setAction({Op, s32}, Legal);
    setAction({Op, 1, s1}, Legal);
  }

  for (unsigned MemOp : {G_LOAD, G_STORE}) {
    for (auto Ty : {s8, s16, s32, p0})
      setAction({MemOp, Ty}, Legal);

    setAction({MemOp, s1}, WidenScalar);
    // And everything's fine in addrspace 0.
    setAction({MemOp, 1, p0}, Legal);
  }

  // Pointer-handling
  setAction({G_FRAME_INDEX, p0}, Legal);
  setAction({G_GLOBAL_VALUE, p0}, Legal);

  setAction({G_GEP, p0}, Legal);
  setAction({G_GEP, 1, s32}, Legal);

  for (auto Ty : {s1, s8, s16})
    setAction({G_GEP, 1, Ty}, WidenScalar);

  // Control-flow
  setAction({G_BRCOND, s1}, Legal);

  // Constants
  for (auto Ty : {s8, s16, s32, p0})
    setAction({TargetOpcode::G_CONSTANT, Ty}, Legal);

  setAction({TargetOpcode::G_CONSTANT, s1}, WidenScalar);
  setAction({TargetOpcode::G_CONSTANT, s64}, NarrowScalar);

  // Extensions
  for (auto Ty : {s8, s16, s32}) {
    setAction({G_ZEXT, Ty}, Legal);
    setAction({G_SEXT, Ty}, Legal);
  }

  for (auto Ty : {s1, s8, s16}) {
    setAction({G_ZEXT, 1, Ty}, Legal);
    setAction({G_SEXT, 1, Ty}, Legal);
  }

  // Comparison
  setAction({G_ICMP, s1}, Legal);

  for (auto Ty : {s8, s16, s32, p0})
    setAction({G_ICMP, 1, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfo64bit() {

  if (!Subtarget.is64Bit())
    return;

  const LLT p0 = LLT::pointer(0, TM.getPointerSize() * 8);
  const LLT s1 = LLT::scalar(1);
  const LLT s8 = LLT::scalar(8);
  const LLT s16 = LLT::scalar(16);
  const LLT s32 = LLT::scalar(32);
  const LLT s64 = LLT::scalar(64);

  for (auto Ty : {p0, s1, s8, s16, s32, s64})
    setAction({G_IMPLICIT_DEF, Ty}, Legal);

  for (unsigned BinOp : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR})
    for (auto Ty : {s8, s16, s32, s64})
      setAction({BinOp, Ty}, Legal);

  for (unsigned MemOp : {G_LOAD, G_STORE}) {
    for (auto Ty : {s8, s16, s32, s64, p0})
      setAction({MemOp, Ty}, Legal);

    setAction({MemOp, s1}, WidenScalar);
    // And everything's fine in addrspace 0.
    setAction({MemOp, 1, p0}, Legal);
  }

  // Pointer-handling
  setAction({G_FRAME_INDEX, p0}, Legal);
  setAction({G_GLOBAL_VALUE, p0}, Legal);

  setAction({G_GEP, p0}, Legal);
  setAction({G_GEP, 1, s32}, Legal);
  setAction({G_GEP, 1, s64}, Legal);

  for (auto Ty : {s1, s8, s16})
    setAction({G_GEP, 1, Ty}, WidenScalar);

  // Control-flow
  setAction({G_BRCOND, s1}, Legal);

  // Constants
  for (auto Ty : {s8, s16, s32, s64, p0})
    setAction({TargetOpcode::G_CONSTANT, Ty}, Legal);

  setAction({TargetOpcode::G_CONSTANT, s1}, WidenScalar);

  // Extensions
  for (auto Ty : {s8, s16, s32, s64}) {
    setAction({G_ZEXT, Ty}, Legal);
    setAction({G_SEXT, Ty}, Legal);
  }

  for (auto Ty : {s1, s8, s16, s32}) {
    setAction({G_ZEXT, 1, Ty}, Legal);
    setAction({G_SEXT, 1, Ty}, Legal);
  }

  // Comparison
  setAction({G_ICMP, s1}, Legal);

  for (auto Ty : {s8, s16, s32, s64, p0})
    setAction({G_ICMP, 1, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoSSE1() {
  if (!Subtarget.hasSSE1())
    return;

  const LLT s32 = LLT::scalar(32);
  const LLT v4s32 = LLT::vector(4, 32);
  const LLT v2s64 = LLT::vector(2, 64);

  for (unsigned BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV})
    for (auto Ty : {s32, v4s32})
      setAction({BinOp, Ty}, Legal);

  for (unsigned MemOp : {G_LOAD, G_STORE})
    for (auto Ty : {v4s32, v2s64})
      setAction({MemOp, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoSSE2() {
  if (!Subtarget.hasSSE2())
    return;

  const LLT s64 = LLT::scalar(64);
  const LLT v16s8 = LLT::vector(16, 8);
  const LLT v8s16 = LLT::vector(8, 16);
  const LLT v4s32 = LLT::vector(4, 32);
  const LLT v2s64 = LLT::vector(2, 64);

  for (unsigned BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV})
    for (auto Ty : {s64, v2s64})
      setAction({BinOp, Ty}, Legal);

  for (unsigned BinOp : {G_ADD, G_SUB})
    for (auto Ty : {v16s8, v8s16, v4s32, v2s64})
      setAction({BinOp, Ty}, Legal);

  setAction({G_MUL, v8s16}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoSSE41() {
  if (!Subtarget.hasSSE41())
    return;

  const LLT v4s32 = LLT::vector(4, 32);

  setAction({G_MUL, v4s32}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoAVX() {
  if (!Subtarget.hasAVX())
    return;

  const LLT v16s8 = LLT::vector(16, 8);
  const LLT v8s16 = LLT::vector(8, 16);
  const LLT v4s32 = LLT::vector(4, 32);
  const LLT v2s64 = LLT::vector(2, 64);

  const LLT v32s8 = LLT::vector(32, 8);
  const LLT v16s16 = LLT::vector(16, 16);
  const LLT v8s32 = LLT::vector(8, 32);
  const LLT v4s64 = LLT::vector(4, 64);

  for (unsigned MemOp : {G_LOAD, G_STORE})
    for (auto Ty : {v8s32, v4s64})
      setAction({MemOp, Ty}, Legal);

  for (auto Ty : {v32s8, v16s16, v8s32, v4s64}) {
    setAction({G_INSERT, Ty}, Legal);
    setAction({G_EXTRACT, 1, Ty}, Legal);
  }
  for (auto Ty : {v16s8, v8s16, v4s32, v2s64}) {
    setAction({G_INSERT, 1, Ty}, Legal);
    setAction({G_EXTRACT, Ty}, Legal);
  }
}

void X86LegalizerInfo::setLegalizerInfoAVX2() {
  if (!Subtarget.hasAVX2())
    return;

  const LLT v32s8 = LLT::vector(32, 8);
  const LLT v16s16 = LLT::vector(16, 16);
  const LLT v8s32 = LLT::vector(8, 32);
  const LLT v4s64 = LLT::vector(4, 64);

  for (unsigned BinOp : {G_ADD, G_SUB})
    for (auto Ty : {v32s8, v16s16, v8s32, v4s64})
      setAction({BinOp, Ty}, Legal);

  for (auto Ty : {v16s16, v8s32})
    setAction({G_MUL, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoAVX512() {
  if (!Subtarget.hasAVX512())
    return;

  const LLT v16s8 = LLT::vector(16, 8);
  const LLT v8s16 = LLT::vector(8, 16);
  const LLT v4s32 = LLT::vector(4, 32);
  const LLT v2s64 = LLT::vector(2, 64);

  const LLT v32s8 = LLT::vector(32, 8);
  const LLT v16s16 = LLT::vector(16, 16);
  const LLT v8s32 = LLT::vector(8, 32);
  const LLT v4s64 = LLT::vector(4, 64);

  const LLT v64s8 = LLT::vector(64, 8);
  const LLT v32s16 = LLT::vector(32, 16);
  const LLT v16s32 = LLT::vector(16, 32);
  const LLT v8s64 = LLT::vector(8, 64);

  for (unsigned BinOp : {G_ADD, G_SUB})
    for (auto Ty : {v16s32, v8s64})
      setAction({BinOp, Ty}, Legal);

  setAction({G_MUL, v16s32}, Legal);

  for (unsigned MemOp : {G_LOAD, G_STORE})
    for (auto Ty : {v16s32, v8s64})
      setAction({MemOp, Ty}, Legal);

  for (auto Ty : {v64s8, v32s16, v16s32, v8s64}) {
    setAction({G_INSERT, Ty}, Legal);
    setAction({G_EXTRACT, 1, Ty}, Legal);
  }
  for (auto Ty : {v32s8, v16s16, v8s32, v4s64, v16s8, v8s16, v4s32, v2s64}) {
    setAction({G_INSERT, 1, Ty}, Legal);
    setAction({G_EXTRACT, Ty}, Legal);
  }

  /************ VLX *******************/
  if (!Subtarget.hasVLX())
    return;

  for (auto Ty : {v4s32, v8s32})
    setAction({G_MUL, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoAVX512DQ() {
  if (!(Subtarget.hasAVX512() && Subtarget.hasDQI()))
    return;

  const LLT v8s64 = LLT::vector(8, 64);

  setAction({G_MUL, v8s64}, Legal);

  /************ VLX *******************/
  if (!Subtarget.hasVLX())
    return;

  const LLT v2s64 = LLT::vector(2, 64);
  const LLT v4s64 = LLT::vector(4, 64);

  for (auto Ty : {v2s64, v4s64})
    setAction({G_MUL, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoAVX512BW() {
  if (!(Subtarget.hasAVX512() && Subtarget.hasBWI()))
    return;

  const LLT v64s8 = LLT::vector(64, 8);
  const LLT v32s16 = LLT::vector(32, 16);

  for (unsigned BinOp : {G_ADD, G_SUB})
    for (auto Ty : {v64s8, v32s16})
      setAction({BinOp, Ty}, Legal);

  setAction({G_MUL, v32s16}, Legal);

  /************ VLX *******************/
  if (!Subtarget.hasVLX())
    return;

  const LLT v8s16 = LLT::vector(8, 16);
  const LLT v16s16 = LLT::vector(16, 16);

  for (auto Ty : {v8s16, v16s16})
    setAction({G_MUL, Ty}, Legal);
}
<commit_msg>[GlobalISel][X86] Refactor X86LegalizerInfo. NFC.<commit_after>//===- X86LegalizerInfo.cpp --------------------------------------*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the targeting of the Machinelegalizer class for X86.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

#include "X86LegalizerInfo.h"
#include "X86Subtarget.h"
#include "X86TargetMachine.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"
#include "llvm/Target/TargetOpcodes.h"

using namespace llvm;
using namespace TargetOpcode;

X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
                                   const X86TargetMachine &TM)
    : Subtarget(STI), TM(TM) {

  setLegalizerInfo32bit();
  setLegalizerInfo64bit();
  setLegalizerInfoSSE1();
  setLegalizerInfoSSE2();
  setLegalizerInfoSSE41();
  setLegalizerInfoAVX();
  setLegalizerInfoAVX2();
  setLegalizerInfoAVX512();
  setLegalizerInfoAVX512DQ();
  setLegalizerInfoAVX512BW();

  computeTables();
}

void X86LegalizerInfo::setLegalizerInfo32bit() {

  const LLT p0 = LLT::pointer(0, TM.getPointerSize() * 8);
  const LLT s1 = LLT::scalar(1);
  const LLT s8 = LLT::scalar(8);
  const LLT s16 = LLT::scalar(16);
  const LLT s32 = LLT::scalar(32);
  const LLT s64 = LLT::scalar(64);

  for (auto Ty : {p0, s1, s8, s16, s32})
    setAction({G_IMPLICIT_DEF, Ty}, Legal);

  for (unsigned BinOp : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR})
    for (auto Ty : {s8, s16, s32})
      setAction({BinOp, Ty}, Legal);

  for (unsigned Op : {G_UADDE}) {
    setAction({Op, s32}, Legal);
    setAction({Op, 1, s1}, Legal);
  }

  for (unsigned MemOp : {G_LOAD, G_STORE}) {
    for (auto Ty : {s8, s16, s32, p0})
      setAction({MemOp, Ty}, Legal);

    setAction({MemOp, s1}, WidenScalar);
    // And everything's fine in addrspace 0.
    setAction({MemOp, 1, p0}, Legal);
  }

  // Pointer-handling
  setAction({G_FRAME_INDEX, p0}, Legal);
  setAction({G_GLOBAL_VALUE, p0}, Legal);

  setAction({G_GEP, p0}, Legal);
  setAction({G_GEP, 1, s32}, Legal);

  for (auto Ty : {s1, s8, s16})
    setAction({G_GEP, 1, Ty}, WidenScalar);

  // Control-flow
  setAction({G_BRCOND, s1}, Legal);

  // Constants
  for (auto Ty : {s8, s16, s32, p0})
    setAction({TargetOpcode::G_CONSTANT, Ty}, Legal);

  setAction({TargetOpcode::G_CONSTANT, s1}, WidenScalar);
  setAction({TargetOpcode::G_CONSTANT, s64}, NarrowScalar);

  // Extensions
  for (auto Ty : {s8, s16, s32}) {
    setAction({G_ZEXT, Ty}, Legal);
    setAction({G_SEXT, Ty}, Legal);
  }

  for (auto Ty : {s1, s8, s16}) {
    setAction({G_ZEXT, 1, Ty}, Legal);
    setAction({G_SEXT, 1, Ty}, Legal);
  }

  // Comparison
  setAction({G_ICMP, s1}, Legal);

  for (auto Ty : {s8, s16, s32, p0})
    setAction({G_ICMP, 1, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfo64bit() {

  if (!Subtarget.is64Bit())
    return;

  const LLT s32 = LLT::scalar(32);
  const LLT s64 = LLT::scalar(64);

  setAction({G_IMPLICIT_DEF, s64}, Legal);

  for (unsigned BinOp : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR})
    setAction({BinOp, s64}, Legal);

  for (unsigned MemOp : {G_LOAD, G_STORE}) {
    setAction({MemOp, s64}, Legal);
  }

  // Pointer-handling
  setAction({G_GEP, 1, s64}, Legal);

  // Constants
  setAction({TargetOpcode::G_CONSTANT, s64}, Legal);

  // Extensions
  setAction({G_ZEXT, s64}, Legal);
  setAction({G_SEXT, s64}, Legal);

  setAction({G_ZEXT, 1, s32}, Legal);
  setAction({G_SEXT, 1, s32}, Legal);

  // Comparison
  setAction({G_ICMP, 1, s64}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoSSE1() {
  if (!Subtarget.hasSSE1())
    return;

  const LLT s32 = LLT::scalar(32);
  const LLT v4s32 = LLT::vector(4, 32);
  const LLT v2s64 = LLT::vector(2, 64);

  for (unsigned BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV})
    for (auto Ty : {s32, v4s32})
      setAction({BinOp, Ty}, Legal);

  for (unsigned MemOp : {G_LOAD, G_STORE})
    for (auto Ty : {v4s32, v2s64})
      setAction({MemOp, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoSSE2() {
  if (!Subtarget.hasSSE2())
    return;

  const LLT s64 = LLT::scalar(64);
  const LLT v16s8 = LLT::vector(16, 8);
  const LLT v8s16 = LLT::vector(8, 16);
  const LLT v4s32 = LLT::vector(4, 32);
  const LLT v2s64 = LLT::vector(2, 64);

  for (unsigned BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV})
    for (auto Ty : {s64, v2s64})
      setAction({BinOp, Ty}, Legal);

  for (unsigned BinOp : {G_ADD, G_SUB})
    for (auto Ty : {v16s8, v8s16, v4s32, v2s64})
      setAction({BinOp, Ty}, Legal);

  setAction({G_MUL, v8s16}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoSSE41() {
  if (!Subtarget.hasSSE41())
    return;

  const LLT v4s32 = LLT::vector(4, 32);

  setAction({G_MUL, v4s32}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoAVX() {
  if (!Subtarget.hasAVX())
    return;

  const LLT v16s8 = LLT::vector(16, 8);
  const LLT v8s16 = LLT::vector(8, 16);
  const LLT v4s32 = LLT::vector(4, 32);
  const LLT v2s64 = LLT::vector(2, 64);

  const LLT v32s8 = LLT::vector(32, 8);
  const LLT v16s16 = LLT::vector(16, 16);
  const LLT v8s32 = LLT::vector(8, 32);
  const LLT v4s64 = LLT::vector(4, 64);

  for (unsigned MemOp : {G_LOAD, G_STORE})
    for (auto Ty : {v8s32, v4s64})
      setAction({MemOp, Ty}, Legal);

  for (auto Ty : {v32s8, v16s16, v8s32, v4s64}) {
    setAction({G_INSERT, Ty}, Legal);
    setAction({G_EXTRACT, 1, Ty}, Legal);
  }
  for (auto Ty : {v16s8, v8s16, v4s32, v2s64}) {
    setAction({G_INSERT, 1, Ty}, Legal);
    setAction({G_EXTRACT, Ty}, Legal);
  }
}

void X86LegalizerInfo::setLegalizerInfoAVX2() {
  if (!Subtarget.hasAVX2())
    return;

  const LLT v32s8 = LLT::vector(32, 8);
  const LLT v16s16 = LLT::vector(16, 16);
  const LLT v8s32 = LLT::vector(8, 32);
  const LLT v4s64 = LLT::vector(4, 64);

  for (unsigned BinOp : {G_ADD, G_SUB})
    for (auto Ty : {v32s8, v16s16, v8s32, v4s64})
      setAction({BinOp, Ty}, Legal);

  for (auto Ty : {v16s16, v8s32})
    setAction({G_MUL, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoAVX512() {
  if (!Subtarget.hasAVX512())
    return;

  const LLT v16s8 = LLT::vector(16, 8);
  const LLT v8s16 = LLT::vector(8, 16);
  const LLT v4s32 = LLT::vector(4, 32);
  const LLT v2s64 = LLT::vector(2, 64);

  const LLT v32s8 = LLT::vector(32, 8);
  const LLT v16s16 = LLT::vector(16, 16);
  const LLT v8s32 = LLT::vector(8, 32);
  const LLT v4s64 = LLT::vector(4, 64);

  const LLT v64s8 = LLT::vector(64, 8);
  const LLT v32s16 = LLT::vector(32, 16);
  const LLT v16s32 = LLT::vector(16, 32);
  const LLT v8s64 = LLT::vector(8, 64);

  for (unsigned BinOp : {G_ADD, G_SUB})
    for (auto Ty : {v16s32, v8s64})
      setAction({BinOp, Ty}, Legal);

  setAction({G_MUL, v16s32}, Legal);

  for (unsigned MemOp : {G_LOAD, G_STORE})
    for (auto Ty : {v16s32, v8s64})
      setAction({MemOp, Ty}, Legal);

  for (auto Ty : {v64s8, v32s16, v16s32, v8s64}) {
    setAction({G_INSERT, Ty}, Legal);
    setAction({G_EXTRACT, 1, Ty}, Legal);
  }
  for (auto Ty : {v32s8, v16s16, v8s32, v4s64, v16s8, v8s16, v4s32, v2s64}) {
    setAction({G_INSERT, 1, Ty}, Legal);
    setAction({G_EXTRACT, Ty}, Legal);
  }

  /************ VLX *******************/
  if (!Subtarget.hasVLX())
    return;

  for (auto Ty : {v4s32, v8s32})
    setAction({G_MUL, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoAVX512DQ() {
  if (!(Subtarget.hasAVX512() && Subtarget.hasDQI()))
    return;

  const LLT v8s64 = LLT::vector(8, 64);

  setAction({G_MUL, v8s64}, Legal);

  /************ VLX *******************/
  if (!Subtarget.hasVLX())
    return;

  const LLT v2s64 = LLT::vector(2, 64);
  const LLT v4s64 = LLT::vector(4, 64);

  for (auto Ty : {v2s64, v4s64})
    setAction({G_MUL, Ty}, Legal);
}

void X86LegalizerInfo::setLegalizerInfoAVX512BW() {
  if (!(Subtarget.hasAVX512() && Subtarget.hasBWI()))
    return;

  const LLT v64s8 = LLT::vector(64, 8);
  const LLT v32s16 = LLT::vector(32, 16);

  for (unsigned BinOp : {G_ADD, G_SUB})
    for (auto Ty : {v64s8, v32s16})
      setAction({BinOp, Ty}, Legal);

  setAction({G_MUL, v32s16}, Legal);

  /************ VLX *******************/
  if (!Subtarget.hasVLX())
    return;

  const LLT v8s16 = LLT::vector(8, 16);
  const LLT v16s16 = LLT::vector(16, 16);

  for (auto Ty : {v8s16, v16s16})
    setAction({G_MUL, Ty}, Legal);
}
<|endoftext|>


<commit_before>//===--- CommonOptionsParser.cpp - common options for clang tools ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the CommonOptionsParser class used to parse common
//  command-line options for clang tools, so that they can be run as separate
//  command-line applications with a consistent common interface for handling
//  compilation database and input files.
//
//  It provides a common subset of command-line options, common algorithm
//  for locating a compilation database and source files, and help messages
//  for the basic command-line interface.
//
//  It creates a CompilationDatabase and reads common command-line options.
//
//  This class uses the Clang Tooling infrastructure, see
//    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
//  for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/CommandLine.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"

using namespace clang::tooling;
using namespace llvm;

const char *const CommonOptionsParser::HelpMessage =
    "\n"
    "-p <build-path> is used to read a compile command database.\n"
    "\n"
    "\tFor example, it can be a CMake build directory in which a file named\n"
    "\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n"
    "\tCMake option to get this output). When no build path is specified,\n"
    "\ta search for compile_commands.json will be attempted through all\n"
    "\tparent paths of the first input file . See:\n"
    "\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
    "\texample of setting up Clang Tooling on a source tree.\n"
    "\n"
    "<source0> ... specify the paths of source files. These paths are\n"
    "\tlooked up in the compile command database. If the path of a file is\n"
    "\tabsolute, it needs to point into CMake's source tree. If the path is\n"
    "\trelative, the current working directory needs to be in the CMake\n"
    "\tsource tree and the file must be in a subdirectory of the current\n"
    "\tworking directory. \"./\" prefixes in the relative files will be\n"
    "\tautomatically removed, but the rest of a relative path must be a\n"
    "\tsuffix of a path in the compile command database.\n"
    "\n";

namespace {
class ArgumentsAdjustingCompilations : public CompilationDatabase {
public:
  ArgumentsAdjustingCompilations(
      std::unique_ptr<CompilationDatabase> Compilations)
      : Compilations(std::move(Compilations)) {}

  void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
    Adjusters.push_back(Adjuster);
  }

  std::vector<CompileCommand>
  getCompileCommands(StringRef FilePath) const override {
    return adjustCommands(Compilations->getCompileCommands(FilePath));
  }

  std::vector<std::string> getAllFiles() const override {
    return Compilations->getAllFiles();
  }

  std::vector<CompileCommand> getAllCompileCommands() const override {
    return adjustCommands(Compilations->getAllCompileCommands());
  }

private:
  std::unique_ptr<CompilationDatabase> Compilations;
  std::vector<ArgumentsAdjuster> Adjusters;

  std::vector<CompileCommand>
  adjustCommands(std::vector<CompileCommand> Commands) const {
    for (CompileCommand &Command : Commands)
      for (const auto &Adjuster : Adjusters)
        Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename);
    return Commands;
  }
};
} // namespace

CommonOptionsParser::CommonOptionsParser(
    int &argc, const char **argv, cl::OptionCategory &Category,
    llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
  static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);

  static cl::opt<std::string> BuildPath("p", cl::desc("Build path"),
                                        cl::Optional, cl::cat(Category));

  static cl::list<std::string> SourcePaths(
      cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag,
      cl::cat(Category));

  static cl::list<std::string> ArgsAfter(
      "extra-arg",
      cl::desc("Additional argument to append to the compiler command line"),
      cl::cat(Category));

  static cl::list<std::string> ArgsBefore(
      "extra-arg-before",
      cl::desc("Additional argument to prepend to the compiler command line"),
      cl::cat(Category));

  cl::HideUnrelatedOptions(Category);

  Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc,
                                                                   argv));
  cl::ParseCommandLineOptions(argc, argv, Overview);
  SourcePathList = SourcePaths;
  if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) &&
      SourcePathList.empty())
    return;
  if (!Compilations) {
    std::string ErrorMessage;
    if (!BuildPath.empty()) {
      Compilations =
          CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
    } else {
      Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0],
                                                               ErrorMessage);
    }
    if (!Compilations)
      llvm::report_fatal_error(ErrorMessage);
  }
  auto AdjustingCompilations =
      llvm::make_unique<ArgumentsAdjustingCompilations>(
          std::move(Compilations));
  AdjustingCompilations->appendArgumentsAdjuster(
      getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN));
  AdjustingCompilations->appendArgumentsAdjuster(
      getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
  Compilations = std::move(AdjustingCompilations);
}
<commit_msg>Add fall-back mode for clang tools.<commit_after>//===--- CommonOptionsParser.cpp - common options for clang tools ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the CommonOptionsParser class used to parse common
//  command-line options for clang tools, so that they can be run as separate
//  command-line applications with a consistent common interface for handling
//  compilation database and input files.
//
//  It provides a common subset of command-line options, common algorithm
//  for locating a compilation database and source files, and help messages
//  for the basic command-line interface.
//
//  It creates a CompilationDatabase and reads common command-line options.
//
//  This class uses the Clang Tooling infrastructure, see
//    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
//  for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/CommandLine.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"

using namespace clang::tooling;
using namespace llvm;

const char *const CommonOptionsParser::HelpMessage =
    "\n"
    "-p <build-path> is used to read a compile command database.\n"
    "\n"
    "\tFor example, it can be a CMake build directory in which a file named\n"
    "\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n"
    "\tCMake option to get this output). When no build path is specified,\n"
    "\ta search for compile_commands.json will be attempted through all\n"
    "\tparent paths of the first input file . See:\n"
    "\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
    "\texample of setting up Clang Tooling on a source tree.\n"
    "\n"
    "<source0> ... specify the paths of source files. These paths are\n"
    "\tlooked up in the compile command database. If the path of a file is\n"
    "\tabsolute, it needs to point into CMake's source tree. If the path is\n"
    "\trelative, the current working directory needs to be in the CMake\n"
    "\tsource tree and the file must be in a subdirectory of the current\n"
    "\tworking directory. \"./\" prefixes in the relative files will be\n"
    "\tautomatically removed, but the rest of a relative path must be a\n"
    "\tsuffix of a path in the compile command database.\n"
    "\n";

namespace {
class ArgumentsAdjustingCompilations : public CompilationDatabase {
public:
  ArgumentsAdjustingCompilations(
      std::unique_ptr<CompilationDatabase> Compilations)
      : Compilations(std::move(Compilations)) {}

  void appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) {
    Adjusters.push_back(Adjuster);
  }

  std::vector<CompileCommand>
  getCompileCommands(StringRef FilePath) const override {
    return adjustCommands(Compilations->getCompileCommands(FilePath));
  }

  std::vector<std::string> getAllFiles() const override {
    return Compilations->getAllFiles();
  }

  std::vector<CompileCommand> getAllCompileCommands() const override {
    return adjustCommands(Compilations->getAllCompileCommands());
  }

private:
  std::unique_ptr<CompilationDatabase> Compilations;
  std::vector<ArgumentsAdjuster> Adjusters;

  std::vector<CompileCommand>
  adjustCommands(std::vector<CompileCommand> Commands) const {
    for (CompileCommand &Command : Commands)
      for (const auto &Adjuster : Adjusters)
        Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename);
    return Commands;
  }
};
} // namespace

CommonOptionsParser::CommonOptionsParser(
    int &argc, const char **argv, cl::OptionCategory &Category,
    llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
  static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);

  static cl::opt<std::string> BuildPath("p", cl::desc("Build path"),
                                        cl::Optional, cl::cat(Category));

  static cl::list<std::string> SourcePaths(
      cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag,
      cl::cat(Category));

  static cl::list<std::string> ArgsAfter(
      "extra-arg",
      cl::desc("Additional argument to append to the compiler command line"),
      cl::cat(Category));

  static cl::list<std::string> ArgsBefore(
      "extra-arg-before",
      cl::desc("Additional argument to prepend to the compiler command line"),
      cl::cat(Category));

  cl::HideUnrelatedOptions(Category);

  Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv));
  cl::ParseCommandLineOptions(argc, argv, Overview);
  SourcePathList = SourcePaths;
  if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) &&
      SourcePathList.empty())
    return;
  if (!Compilations) {
    std::string ErrorMessage;
    if (!BuildPath.empty()) {
      Compilations =
          CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
    } else {
      Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0],
                                                               ErrorMessage);
    }
    if (!Compilations) {
      llvm::errs() << "Error while trying to load a compilation database:\n"
                   << ErrorMessage << "Running without flags.\n";
      Compilations.reset(
          new FixedCompilationDatabase(".", std::vector<std::string>()));
    }
  }
  auto AdjustingCompilations =
      llvm::make_unique<ArgumentsAdjustingCompilations>(
          std::move(Compilations));
  AdjustingCompilations->appendArgumentsAdjuster(
      getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN));
  AdjustingCompilations->appendArgumentsAdjuster(
      getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
  Compilations = std::move(AdjustingCompilations);
}
<|endoftext|>


<commit_before>#ifndef __LAMBDA_HPP__
#define __LAMBDA_HPP__

#include <type_traits>

namespace Lambda {
	using namespace std;

	struct Unused {
		template<typename... _Arguments>
		Unused(_Arguments&...) {}
	};

	enum True {
		TRUE = 1
	};

	enum False {
		FALSE = 0
	};

	template<bool const _f>
	struct Boolean;

	template <>
	struct Boolean<true> {
		typedef True Type;
		static True constexpr s_Value = TRUE;
	};

	template <>
	struct Boolean<false> {
		typedef False Type;
		static False constexpr s_Value = FALSE;
	};

	template<unsigned int const _i, typename ..._Types>
	struct FindType {
		typedef typename FindType<_i - 1, _Types...>::Type Type;
	};

	template<typename _First, typename ..._Others>
	struct FindType<0, _First, _Others...> {
		typedef _First Type;
	};

	struct Functor {};

	template<typename _Type>
	struct IsFunctor {
		typedef typename remove_cv<typename remove_reference<_Type>::type>::type Clean;
		typedef Boolean<is_base_of<Functor, Clean>::value> BooleanType;
		static typename BooleanType::Type constexpr s_Value = BooleanType::s_Value;
	};

	template<unsigned int const _i>
	struct Bind :
		public Functor
	{
		template<typename _First, typename ..._Others>
		inline typename FindType<_i, _First, _Others...>::Type operator () (_First &&rrFirst, _Others &&...rrOthers) {
			return Bind<_i - 1>()((_Others&&)rrOthers...);
		}
	};

	template<>
	struct Bind<0> :
		public Functor
	{
		template<typename _First, typename ..._Others>
		inline _First operator () (_First &&rrFirst, _Others &&...rrOthers) {
			return rrFirst;
		}
	};

	template<typename _Type, False const _IsFunctor = IsFunctor<_Type>::s_Value>
	struct Constant :
		public Functor
	{
		_Type m_Value;

		explicit Constant(_Type &&a_rrValue)
			:
		m_Value((_Type&&)a_rrValue) {}

		template<typename ..._Arguments>
		inline _Type operator () (_Arguments&&...) {
			return m_Value;
		}
	};
}

template<typename _Operand>
inline Lambda::Constant<_Operand> _0(_Operand &&rrOperand) {
	return Lambda::Constant<_Operand>((_Operand&&)rrOperand);
}

static Lambda::Bind<0> _1;
static Lambda::Bind<1> _2;
static Lambda::Bind<2> _3;
static Lambda::Bind<3> _4;
static Lambda::Bind<4> _5;
static Lambda::Bind<5> _6;
static Lambda::Bind<6> _7;
static Lambda::Bind<7> _8;
static Lambda::Bind<8> _9;
static Lambda::Bind<9> _10;

static Lambda::Unused g_Unused = Lambda::Unused(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10);

#define LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(Operator, Name) \
	template<typename _Operand, True const _IsFunctor = IsFunctor<_Operand>::s_Value> \
	struct Name : \
		public UnaryFunctor \
	{ \
		_Operand m_Operand; \
		explicit Name(_Operand &&a_rrOperand) \
			: \
		m_Operand((_Operand&&)a_rrOperand) {} \
		template<typename ..._Arguments> \
		inline auto operator () (_Arguments &&...rrArguments) -> decltype(Operator(m_Operand((_Arguments&&)rrArguments...))) { \
			return Operator(m_Operand((_Arguments&&)rrArguments...)); \
		} \
	};

#define LAMBDA_POSTFIX_UNARY_FUNCTOR_CLASS(Operator, Name) \
	template<typename _Operand, True const _IsFunctor = IsFunctor<_Operand>::s_Value> \
	struct Name : \
		public UnaryFunctor \
	{ \
		_Operand m_Operand; \
		explicit Name(_Operand &&a_rrOperand) \
			: \
		m_Operand((_Operand&&)a_rrOperand) {} \
		template<typename ..._Arguments> \
		inline auto operator () (_Arguments &&...rrArguments) -> decltype((m_Operand((_Arguments&&)rrArguments...))Operator) { \
			return (m_Operand((_Arguments&&)rrArguments...))Operator; \
		} \
	};

namespace Lambda {
	struct UnaryFunctor : public Functor {};

	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(&, Address)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(*, Indirection)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(+, UnaryPlus)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(-, UnaryMinus)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(!, LogicalNot)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(~, BitwiseNot)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(++, PreIncrement)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(--, PreDecrement)
	LAMBDA_POSTFIX_UNARY_FUNCTOR_CLASS(++, PostIncrement)
	LAMBDA_POSTFIX_UNARY_FUNCTOR_CLASS(--, PostDecrement)
}

#define LAMBDA_PREFIX_UNARY_OPERATOR(Operator, Name) \
	template<typename _Operand> \
	inline Lambda::Name<_Operand> operator Operator (_Operand &&rrOperand) { \
		return Lambda::Name<_Operand>((_Operand&&)rrOperand); \
	}

LAMBDA_PREFIX_UNARY_OPERATOR(&, Address)
LAMBDA_PREFIX_UNARY_OPERATOR(*, Indirection)
LAMBDA_PREFIX_UNARY_OPERATOR(+, UnaryPlus)
LAMBDA_PREFIX_UNARY_OPERATOR(-, UnaryMinus)
LAMBDA_PREFIX_UNARY_OPERATOR(!, LogicalNot)
LAMBDA_PREFIX_UNARY_OPERATOR(~, BitwiseNot)
LAMBDA_PREFIX_UNARY_OPERATOR(++, PreIncrement)
LAMBDA_PREFIX_UNARY_OPERATOR(--, PreDecrement)

#define LAMBDA_BINARY_FUNCTOR_CLASS(Operator, Name) \
	template<typename _Left, typename _Right, \
		True const _LeftIsFunctor = IsFunctor<_Left>::s_Value, \
		True const _RightIsFunctor = IsFunctor<_Right>::s_Value> \
	struct Name : \
		public BinaryFunctor \
	{ \
		_Left m_Left; \
		_Right m_Right; \
		Name(_Left &&a_rrLeft, _Right &&a_rrRight) \
			: \
		m_Left((_Left&&)a_rrLeft), \
			m_Right((_Right&&)a_rrRight) {} \
		template<typename ..._Arguments> \
		inline auto operator () (_Arguments &&...rrArguments) -> decltype((m_Left((_Arguments&&)rrArguments...)) Operator (m_Right((_Arguments&&)rrArguments...))) { \
			return (m_Left((_Arguments&&)rrArguments...)) Operator (m_Right((_Arguments&&)rrArguments...)); \
		} \
	};

#define LAMBDA_COMMA ,

namespace Lambda {
	struct BinaryFunctor : public Functor {};

	LAMBDA_BINARY_FUNCTOR_CLASS(+, BinaryPlus)
	LAMBDA_BINARY_FUNCTOR_CLASS(+=, CompoundPlus)
	LAMBDA_BINARY_FUNCTOR_CLASS(-, BinaryMinus)
	LAMBDA_BINARY_FUNCTOR_CLASS(-=, CompoundMinus)
	LAMBDA_BINARY_FUNCTOR_CLASS(*, Multiply)
	LAMBDA_BINARY_FUNCTOR_CLASS(*=, CompoundMultiply)
	LAMBDA_BINARY_FUNCTOR_CLASS(/, Divide)
	LAMBDA_BINARY_FUNCTOR_CLASS(/=, CompoundDivide)
	LAMBDA_BINARY_FUNCTOR_CLASS(%, Modulus)
	LAMBDA_BINARY_FUNCTOR_CLASS(%=, CompoundModulus)
	LAMBDA_BINARY_FUNCTOR_CLASS(&, BitwiseAnd)
	LAMBDA_BINARY_FUNCTOR_CLASS(|, BitwiseOr)
	LAMBDA_BINARY_FUNCTOR_CLASS(^, BitwiseXor)
	LAMBDA_BINARY_FUNCTOR_CLASS(&=, CompoundAnd)
	LAMBDA_BINARY_FUNCTOR_CLASS(|=, CompoundOr)
	LAMBDA_BINARY_FUNCTOR_CLASS(^=, CompoundXor)
	LAMBDA_BINARY_FUNCTOR_CLASS(&&, LogicalAnd)
	LAMBDA_BINARY_FUNCTOR_CLASS(||, LogicalOr)
	LAMBDA_BINARY_FUNCTOR_CLASS(<<, LeftShift)
	LAMBDA_BINARY_FUNCTOR_CLASS(<<=, CompoundLeftShift)
	LAMBDA_BINARY_FUNCTOR_CLASS(>>, RightShift)
	LAMBDA_BINARY_FUNCTOR_CLASS(>>=, CompoundRightShift)
	LAMBDA_BINARY_FUNCTOR_CLASS(==, Equals)
	LAMBDA_BINARY_FUNCTOR_CLASS(!=, NotEqual)
	LAMBDA_BINARY_FUNCTOR_CLASS(<, LessThan)
	LAMBDA_BINARY_FUNCTOR_CLASS(>, GreaterThan)
	LAMBDA_BINARY_FUNCTOR_CLASS(<=, LessThanOrEqualTo)
	LAMBDA_BINARY_FUNCTOR_CLASS(>=, GreaterThanOrEqualTo)
	LAMBDA_BINARY_FUNCTOR_CLASS(LAMBDA_COMMA, Comma)

	template<typename _Left, typename _Right,
		True const _LeftIsFunctor = IsFunctor<_Left>::s_Value,
		True const _RightIsFunctor = IsFunctor<_Right>::s_Value>
	struct Subscript :
		public BinaryFunctor
	{
		_Left m_Left;
		_Right m_Right;

		Subscript(_Left &&a_rrLeft, _Right &&a_rrRight)
			:
		m_Left((_Left&&)a_rrLeft),
			m_Right((_Right&&)a_rrRight) {}

		template<typename ..._Arguments>
		inline auto operator () (_Arguments &&...rrArguments) -> decltype((m_Left((_Arguments&&)rrArguments...))[(m_Right((_Arguments&&)rrArguments...))]) {
			return (m_Left((_Arguments&&)rrArguments...))[(m_Right((_Arguments&&)rrArguments...))];
		}
	};
}

#define LAMBDA_BINARY_OPERATOR(Operator, Name) \
	template<typename _Left, typename _Right> \
	inline Lambda::Name<_Left, _Right> operator Operator (_Left &&rrLeft, _Right &&rrRight) { \
		return Lambda::Name<_Left, _Right>((_Left&&)rrLeft, (_Right&&)rrRight); \
	} \
	template<typename _Left, typename _Right> \
	inline Lambda::Name<Lambda::Constant<_Left>, _Right> operator Operator (_Left &&rrLeft, _Right &&rrRight) { \
		return Lambda::Name<Lambda::Constant<_Left>, _Right>(Lambda::Constant<_Left>((_Left&&)rrLeft), (_Right&&)rrRight); \
	} \
	template<typename _Left, typename _Right> \
	inline Lambda::Name<_Left, Lambda::Constant<_Right>> operator Operator (_Left &&rrLeft, _Right &&rrRight) { \
		return Lambda::Name<_Left, Lambda::Constant<_Right>>((_Left&&)rrLeft, Lambda::Constant<_Right>((_Right&&)rrRight)); \
	}

LAMBDA_BINARY_OPERATOR(+, BinaryPlus)
LAMBDA_BINARY_OPERATOR(+=, CompoundPlus)
LAMBDA_BINARY_OPERATOR(-, BinaryMinus)
LAMBDA_BINARY_OPERATOR(-=, CompoundMinus)
LAMBDA_BINARY_OPERATOR(*, Multiply)
LAMBDA_BINARY_OPERATOR(*=, CompoundMultiply)
LAMBDA_BINARY_OPERATOR(/, Divide)
LAMBDA_BINARY_OPERATOR(/=, CompoundDivide)
LAMBDA_BINARY_OPERATOR(%, Modulus)
LAMBDA_BINARY_OPERATOR(%=, CompoundModulus)
LAMBDA_BINARY_OPERATOR(&, BitwiseAnd)
LAMBDA_BINARY_OPERATOR(|, BitwiseOr)
LAMBDA_BINARY_OPERATOR(^, BitwiseXor)
LAMBDA_BINARY_OPERATOR(&=, CompoundAnd)
LAMBDA_BINARY_OPERATOR(|=, CompoundOr)
LAMBDA_BINARY_OPERATOR(^=, CompoundXor)
LAMBDA_BINARY_OPERATOR(&&, LogicalAnd)
LAMBDA_BINARY_OPERATOR(||, LogicalOr)
LAMBDA_BINARY_OPERATOR(<<, LeftShift)
LAMBDA_BINARY_OPERATOR(<<=, CompoundLeftShift)
LAMBDA_BINARY_OPERATOR(>>, RightShift)
LAMBDA_BINARY_OPERATOR(>>=, CompoundRightShift)
LAMBDA_BINARY_OPERATOR(==, Equals)
LAMBDA_BINARY_OPERATOR(!=, NotEqual)
LAMBDA_BINARY_OPERATOR(<, LessThan)
LAMBDA_BINARY_OPERATOR(>, GreaterThan)
LAMBDA_BINARY_OPERATOR(<=, LessThanOrEqualTo)
LAMBDA_BINARY_OPERATOR(>=, GreaterThanOrEqualTo)
//LAMBDA_BINARY_OPERATOR(LAMBDA_COMMA, Comma)

#endif
<commit_msg>Re-enabling comma operator<commit_after>#ifndef __LAMBDA_HPP__
#define __LAMBDA_HPP__

#include <type_traits>

namespace Lambda {
	using namespace std;

	struct Unused {
		template<typename... _Arguments>
		Unused(_Arguments&...) {}
	};

	enum True {
		TRUE = 1
	};

	enum False {
		FALSE = 0
	};

	template<bool const _f>
	struct Boolean;

	template <>
	struct Boolean<true> {
		typedef True Type;
		static True constexpr s_Value = TRUE;
	};

	template <>
	struct Boolean<false> {
		typedef False Type;
		static False constexpr s_Value = FALSE;
	};

	template<unsigned int const _i, typename ..._Types>
	struct FindType {
		typedef typename FindType<_i - 1, _Types...>::Type Type;
	};

	template<typename _First, typename ..._Others>
	struct FindType<0, _First, _Others...> {
		typedef _First Type;
	};

	struct Functor {};

	template<typename _Type>
	struct IsFunctor {
		typedef typename remove_cv<typename remove_reference<_Type>::type>::type Clean;
		typedef Boolean<is_base_of<Functor, Clean>::value> BooleanType;
		static typename BooleanType::Type constexpr s_Value = BooleanType::s_Value;
	};

	template<unsigned int const _i>
	struct Bind :
		public Functor
	{
		template<typename _First, typename ..._Others>
		inline typename FindType<_i, _First, _Others...>::Type operator () (_First &&rrFirst, _Others &&...rrOthers) {
			return Bind<_i - 1>()((_Others&&)rrOthers...);
		}
	};

	template<>
	struct Bind<0> :
		public Functor
	{
		template<typename _First, typename ..._Others>
		inline _First operator () (_First &&rrFirst, _Others &&...rrOthers) {
			return rrFirst;
		}
	};

	template<typename _Type, False const _IsFunctor = IsFunctor<_Type>::s_Value>
	struct Constant :
		public Functor
	{
		_Type m_Value;

		explicit Constant(_Type &&a_rrValue)
			:
		m_Value((_Type&&)a_rrValue) {}

		template<typename ..._Arguments>
		inline _Type operator () (_Arguments&&...) {
			return m_Value;
		}
	};
}

template<typename _Operand>
inline Lambda::Constant<_Operand> _0(_Operand &&rrOperand) {
	return Lambda::Constant<_Operand>((_Operand&&)rrOperand);
}

static Lambda::Bind<0> _1;
static Lambda::Bind<1> _2;
static Lambda::Bind<2> _3;
static Lambda::Bind<3> _4;
static Lambda::Bind<4> _5;
static Lambda::Bind<5> _6;
static Lambda::Bind<6> _7;
static Lambda::Bind<7> _8;
static Lambda::Bind<8> _9;
static Lambda::Bind<9> _10;

static Lambda::Unused g_Unused = Lambda::Unused(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10);

#define LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(Operator, Name) \
	template<typename _Operand, True const _IsFunctor = IsFunctor<_Operand>::s_Value> \
	struct Name : \
		public UnaryFunctor \
	{ \
		_Operand m_Operand; \
		explicit Name(_Operand &&a_rrOperand) \
			: \
		m_Operand((_Operand&&)a_rrOperand) {} \
		template<typename ..._Arguments> \
		inline auto operator () (_Arguments &&...rrArguments) -> decltype(Operator(m_Operand((_Arguments&&)rrArguments...))) { \
			return Operator(m_Operand((_Arguments&&)rrArguments...)); \
		} \
	};

#define LAMBDA_POSTFIX_UNARY_FUNCTOR_CLASS(Operator, Name) \
	template<typename _Operand, True const _IsFunctor = IsFunctor<_Operand>::s_Value> \
	struct Name : \
		public UnaryFunctor \
	{ \
		_Operand m_Operand; \
		explicit Name(_Operand &&a_rrOperand) \
			: \
		m_Operand((_Operand&&)a_rrOperand) {} \
		template<typename ..._Arguments> \
		inline auto operator () (_Arguments &&...rrArguments) -> decltype((m_Operand((_Arguments&&)rrArguments...))Operator) { \
			return (m_Operand((_Arguments&&)rrArguments...))Operator; \
		} \
	};

namespace Lambda {
	struct UnaryFunctor : public Functor {};

	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(&, Address)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(*, Indirection)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(+, UnaryPlus)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(-, UnaryMinus)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(!, LogicalNot)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(~, BitwiseNot)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(++, PreIncrement)
	LAMBDA_PREFIX_UNARY_FUNCTOR_CLASS(--, PreDecrement)
	LAMBDA_POSTFIX_UNARY_FUNCTOR_CLASS(++, PostIncrement)
	LAMBDA_POSTFIX_UNARY_FUNCTOR_CLASS(--, PostDecrement)
}

#define LAMBDA_PREFIX_UNARY_OPERATOR(Operator, Name) \
	template<typename _Operand> \
	inline Lambda::Name<_Operand> operator Operator (_Operand &&rrOperand) { \
		return Lambda::Name<_Operand>((_Operand&&)rrOperand); \
	}

LAMBDA_PREFIX_UNARY_OPERATOR(&, Address)
LAMBDA_PREFIX_UNARY_OPERATOR(*, Indirection)
LAMBDA_PREFIX_UNARY_OPERATOR(+, UnaryPlus)
LAMBDA_PREFIX_UNARY_OPERATOR(-, UnaryMinus)
LAMBDA_PREFIX_UNARY_OPERATOR(!, LogicalNot)
LAMBDA_PREFIX_UNARY_OPERATOR(~, BitwiseNot)
LAMBDA_PREFIX_UNARY_OPERATOR(++, PreIncrement)
LAMBDA_PREFIX_UNARY_OPERATOR(--, PreDecrement)

#define LAMBDA_BINARY_FUNCTOR_CLASS(Operator, Name) \
	template<typename _Left, typename _Right, \
		True const _LeftIsFunctor = IsFunctor<_Left>::s_Value, \
		True const _RightIsFunctor = IsFunctor<_Right>::s_Value> \
	struct Name : \
		public BinaryFunctor \
	{ \
		_Left m_Left; \
		_Right m_Right; \
		Name(_Left &&a_rrLeft, _Right &&a_rrRight) \
			: \
		m_Left((_Left&&)a_rrLeft), \
			m_Right((_Right&&)a_rrRight) {} \
		template<typename ..._Arguments> \
		inline auto operator () (_Arguments &&...rrArguments) -> decltype((m_Left((_Arguments&&)rrArguments...)) Operator (m_Right((_Arguments&&)rrArguments...))) { \
			return (m_Left((_Arguments&&)rrArguments...)) Operator (m_Right((_Arguments&&)rrArguments...)); \
		} \
	};

#define LAMBDA_COMMA ,

namespace Lambda {
	struct BinaryFunctor : public Functor {};

	LAMBDA_BINARY_FUNCTOR_CLASS(+, BinaryPlus)
	LAMBDA_BINARY_FUNCTOR_CLASS(+=, CompoundPlus)
	LAMBDA_BINARY_FUNCTOR_CLASS(-, BinaryMinus)
	LAMBDA_BINARY_FUNCTOR_CLASS(-=, CompoundMinus)
	LAMBDA_BINARY_FUNCTOR_CLASS(*, Multiply)
	LAMBDA_BINARY_FUNCTOR_CLASS(*=, CompoundMultiply)
	LAMBDA_BINARY_FUNCTOR_CLASS(/, Divide)
	LAMBDA_BINARY_FUNCTOR_CLASS(/=, CompoundDivide)
	LAMBDA_BINARY_FUNCTOR_CLASS(%, Modulus)
	LAMBDA_BINARY_FUNCTOR_CLASS(%=, CompoundModulus)
	LAMBDA_BINARY_FUNCTOR_CLASS(&, BitwiseAnd)
	LAMBDA_BINARY_FUNCTOR_CLASS(|, BitwiseOr)
	LAMBDA_BINARY_FUNCTOR_CLASS(^, BitwiseXor)
	LAMBDA_BINARY_FUNCTOR_CLASS(&=, CompoundAnd)
	LAMBDA_BINARY_FUNCTOR_CLASS(|=, CompoundOr)
	LAMBDA_BINARY_FUNCTOR_CLASS(^=, CompoundXor)
	LAMBDA_BINARY_FUNCTOR_CLASS(&&, LogicalAnd)
	LAMBDA_BINARY_FUNCTOR_CLASS(||, LogicalOr)
	LAMBDA_BINARY_FUNCTOR_CLASS(<<, LeftShift)
	LAMBDA_BINARY_FUNCTOR_CLASS(<<=, CompoundLeftShift)
	LAMBDA_BINARY_FUNCTOR_CLASS(>>, RightShift)
	LAMBDA_BINARY_FUNCTOR_CLASS(>>=, CompoundRightShift)
	LAMBDA_BINARY_FUNCTOR_CLASS(==, Equals)
	LAMBDA_BINARY_FUNCTOR_CLASS(!=, NotEqual)
	LAMBDA_BINARY_FUNCTOR_CLASS(<, LessThan)
	LAMBDA_BINARY_FUNCTOR_CLASS(>, GreaterThan)
	LAMBDA_BINARY_FUNCTOR_CLASS(<=, LessThanOrEqualTo)
	LAMBDA_BINARY_FUNCTOR_CLASS(>=, GreaterThanOrEqualTo)
	LAMBDA_BINARY_FUNCTOR_CLASS(LAMBDA_COMMA, Comma)

	template<typename _Left, typename _Right,
		True const _LeftIsFunctor = IsFunctor<_Left>::s_Value,
		True const _RightIsFunctor = IsFunctor<_Right>::s_Value>
	struct Subscript :
		public BinaryFunctor
	{
		_Left m_Left;
		_Right m_Right;

		Subscript(_Left &&a_rrLeft, _Right &&a_rrRight)
			:
		m_Left((_Left&&)a_rrLeft),
			m_Right((_Right&&)a_rrRight) {}

		template<typename ..._Arguments>
		inline auto operator () (_Arguments &&...rrArguments) -> decltype((m_Left((_Arguments&&)rrArguments...))[(m_Right((_Arguments&&)rrArguments...))]) {
			return (m_Left((_Arguments&&)rrArguments...))[(m_Right((_Arguments&&)rrArguments...))];
		}
	};
}

#define LAMBDA_BINARY_OPERATOR(Operator, Name) \
	template<typename _Left, typename _Right> \
	inline Lambda::Name<_Left, _Right> operator Operator (_Left &&rrLeft, _Right &&rrRight) { \
		return Lambda::Name<_Left, _Right>((_Left&&)rrLeft, (_Right&&)rrRight); \
	} \
	template<typename _Left, typename _Right> \
	inline Lambda::Name<Lambda::Constant<_Left>, _Right> operator Operator (_Left &&rrLeft, _Right &&rrRight) { \
		return Lambda::Name<Lambda::Constant<_Left>, _Right>(Lambda::Constant<_Left>((_Left&&)rrLeft), (_Right&&)rrRight); \
	} \
	template<typename _Left, typename _Right> \
	inline Lambda::Name<_Left, Lambda::Constant<_Right>> operator Operator (_Left &&rrLeft, _Right &&rrRight) { \
		return Lambda::Name<_Left, Lambda::Constant<_Right>>((_Left&&)rrLeft, Lambda::Constant<_Right>((_Right&&)rrRight)); \
	}

LAMBDA_BINARY_OPERATOR(+, BinaryPlus)
LAMBDA_BINARY_OPERATOR(+=, CompoundPlus)
LAMBDA_BINARY_OPERATOR(-, BinaryMinus)
LAMBDA_BINARY_OPERATOR(-=, CompoundMinus)
LAMBDA_BINARY_OPERATOR(*, Multiply)
LAMBDA_BINARY_OPERATOR(*=, CompoundMultiply)
LAMBDA_BINARY_OPERATOR(/, Divide)
LAMBDA_BINARY_OPERATOR(/=, CompoundDivide)
LAMBDA_BINARY_OPERATOR(%, Modulus)
LAMBDA_BINARY_OPERATOR(%=, CompoundModulus)
LAMBDA_BINARY_OPERATOR(&, BitwiseAnd)
LAMBDA_BINARY_OPERATOR(|, BitwiseOr)
LAMBDA_BINARY_OPERATOR(^, BitwiseXor)
LAMBDA_BINARY_OPERATOR(&=, CompoundAnd)
LAMBDA_BINARY_OPERATOR(|=, CompoundOr)
LAMBDA_BINARY_OPERATOR(^=, CompoundXor)
LAMBDA_BINARY_OPERATOR(&&, LogicalAnd)
LAMBDA_BINARY_OPERATOR(||, LogicalOr)
LAMBDA_BINARY_OPERATOR(<<, LeftShift)
LAMBDA_BINARY_OPERATOR(<<=, CompoundLeftShift)
LAMBDA_BINARY_OPERATOR(>>, RightShift)
LAMBDA_BINARY_OPERATOR(>>=, CompoundRightShift)
LAMBDA_BINARY_OPERATOR(==, Equals)
LAMBDA_BINARY_OPERATOR(!=, NotEqual)
LAMBDA_BINARY_OPERATOR(<, LessThan)
LAMBDA_BINARY_OPERATOR(>, GreaterThan)
LAMBDA_BINARY_OPERATOR(<=, LessThanOrEqualTo)
LAMBDA_BINARY_OPERATOR(>=, GreaterThanOrEqualTo)
LAMBDA_BINARY_OPERATOR(LAMBDA_COMMA, Comma)

#endif
<|endoftext|>


<commit_before>/*******************************************************************************
 * thrill/common/fast_string.hpp
 *
 * (Hopefully) fast static-length string implementation.
 *
 * Part of Project Thrill.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef THRILL_COMMON_FAST_STRING_HEADER
#define THRILL_COMMON_FAST_STRING_HEADER

#include <thrill/common/logger.hpp>
#include <thrill/data/serialization.hpp>

#if __GNUC__ && !__clang__
#include <bits/functional_hash.h>
#endif

#include <algorithm>
#include <string>

namespace thrill {
namespace common {

/**
 * FastString is a fast implementation of a string, which is basically only
 * a char pointer and a length. The FastString is defined by the char array given
 * by those parameters. A copy assignment or copy constructor actually allocates
 * memory for the data. This allows both non-allocating quick references and persistent
 * storage of strings.
 */
class FastString
{
public:
    /**
     * Default constructor for a FastString.
     * Doesn't do anything.
     */
    FastString() : size_(0) { }

    /**
     * Copy constructor for a new FastString. Actually allocates memory.
     * \param input Input FastString
     * \return Copy of input
     */
    FastString(const FastString& input) {
        char* begin = new char[input.size_];
        std::copy(input.data_, input.data_ + input.size_, begin);
        data_ = begin;
        size_ = input.size_;
        owns_data_ = true;
    }

    /**
     * Move constructor for a new FastString. Steals data ownership.
     */
    FastString(FastString&& other)
        : FastString(other.data_, other.size_, other.owns_data_) {
        other.owns_data_ = false;
    }

    /**
     * Destructor for a FastString. If it holds data, this data gets freed.
     */
    ~FastString() {
        if (owns_data_) {
            delete[] (data_);
        }
    }

    /**
     * Creates a new reference FastString, given a const char* and the size of the FastString.
     * \param data Pointer to start of data
     * \param size Size of data in bytes.
     * \return New FastString object.
     */
    static FastString Ref(const char* data, size_t size) {
        return FastString(data, size, false);
    }

    /**
     * Creates a new reference FastString, given a const iterator to a std::string
     * and the size of the FastString.
     * \param data Pointer to start of data
     * \param size Size of data in bytes.
     * \return New FastString object.
     */
    static FastString Ref(const std::string::const_iterator& data, size_t size) {
        return FastString(&(*data), size, false);
    }

    /**
     * Creates a new FastString and takes data ownership,
     * given a const char* and the size of the FastString.
     * \param data Pointer to start of data
     * \param size Size of data in bytes.
     * \return New FastString object.
     */
    static FastString Take(const char* data, size_t size) {
        return FastString(data, size, true);
    }

    /**
     * Creates a new FastString and copies it's data.
     * \param data Pointer to start of data
     * \param size Size of data in bytes.
     * \return New FastString object.
     */
    static FastString Copy(const char* data, size_t size) {
        char* mem = new char[size];
        std::copy(data, data + size, mem);
        return FastString(mem, size, true);
    }

    /**
     * Creates a new FastString and copies it's data.
     * \param input Input string, which the new FastString is a copy of
     * \return New FastString object.
     */
    static FastString Copy(const std::string& input) {
        return Copy(input.c_str(), input.size());
    }

    /**
     * Returns a pointer to the start of the data.
     */
    const char * Data() const {
        return data_;
    }

    /**
     * Returns the size of this FastString
     */
    size_t Size() const {
        return size_;
    }

    /**
     * Copy assignment operator.
     * \param other copied FastString
     * \return reference to this FastString
     */
    FastString& operator = (const FastString& other) {
        if (owns_data_) delete[] (data_);
        char* mem = new char[other.size_];
        std::copy(other.data_, other.data_ + other.size_, mem);
        data_ = mem;
        size_ = other.size_;
        owns_data_ = true;
        return *this;
    }

    /**
     * Move assignment operator
     * \param other moved FastString
     * \return reference to this FastString
     */
    FastString& operator = (FastString&& other) {
        if (owns_data_) delete[] (data_);
        data_ = std::move(other.data_);
        size_ = other.Size();
        owns_data_ = other.owns_data_;
        other.owns_data_ = false;
        return *this;
    }

    /**
     * Equality operator to compare a FastString with an std::string
     * \param other Comparison string
     * \return true, if data is equal
     */
    bool operator == (const std::string& other) const {
        return size_ == other.size() &&
               std::equal(data_, data_ + size_, other.c_str());
    }

    /**
     * Inequality operator to compare a FastString with an std::string
     * \param other Comparison string
     * \return false, if data is equal
     */
    bool operator != (const std::string& other) const {
        return !(operator == (other));
    }

    /**
     * Equality operator to compare a FastString with another FastString
     * \param other Comparison FastString
     * \return true, if data is equal
     */
    bool operator == (const FastString& other) const {
        return size_ == other.size_ &&
               std::equal(data_, data_ + size_, other.data_);
    }

    /**
     * Inequality operator to compare a FastString with another FastString
     * \param other Comparison FastString
     * \return false, if data is equal
     */
    bool operator != (const FastString& other) const {
        return !(operator == (other));
    }

    /**
     * Make FastString ostreamable
     * \param os ostream
     * \param fs FastString to stream
     */
    friend std::ostream& operator << (std::ostream& os, const FastString& fs) {
        return os.write(fs.Data(), fs.Size());
    }

    /**
     * Returns the data of this FastString as an std::string
     * \return This FastString as an std::string
     */
    std::string ToString() const {
        return std::string(data_, size_);
    }

protected:
    /**
     * Internal constructor, which creates a new FastString and sets parameters
     * \param data Pointer to data
     * \param size Size of data in bytes
     * \param owns_data True, if this FastString has ownership of data
     */
    FastString(const char* data, size_t size, bool owns_data)
        : data_(data), size_(size), owns_data_(owns_data) { }

    //! Pointer to data
    const char* data_ = 0;
    //! Size of data
    size_t size_;
    //! True, if this FastString has ownership of data
    bool owns_data_ = false;
};

} // namespace common

namespace data {

template <typename Archive>
struct Serialization<Archive, common::FastString>
{
    static void Serialize(const common::FastString& fs, Archive& ar) {
        ar.PutVarint(fs.Size()).Append(fs.Data(), fs.Size());
    }

    static common::FastString Deserialize(Archive& ar) {
        uint64_t size = ar.GetVarint();
        char* outdata = new char[size];
        ar.Read(outdata, size);
        return common::FastString::Take(outdata, size);
    }

    static const bool   is_fixed_size = false;
    static const size_t fixed_size = 0;
};

} // namespace data
} // namespace thrill

namespace std {
template <>
struct hash<thrill::common::FastString>
{
    size_t operator () (const thrill::common::FastString& fs) const {
#if __GNUC__ && !__clang__
        return std::_Hash_impl::hash(fs.Data(), fs.Size());
#else
        // Only gcc has bits/functional_hash.h, using other hash function.
        // taken from: http://www.cse.yorku.ca/~oz/hash.html
        unsigned int hash = 5381;
        for (size_t ctr = 0; ctr < fs.Size(); ctr++) {
            // hash * 33 + c
            hash = ((hash << 5) + hash) + *(fs.Data() + ctr);
        }
        return hash;
#endif
    }
};

} // namespace std

#endif // !THRILL_COMMON_FAST_STRING_HEADER

/******************************************************************************/
<commit_msg>Fixing FastString: always use the low-level hash function.<commit_after>/*******************************************************************************
 * thrill/common/fast_string.hpp
 *
 * (Hopefully) fast static-length string implementation.
 *
 * Part of Project Thrill.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef THRILL_COMMON_FAST_STRING_HEADER
#define THRILL_COMMON_FAST_STRING_HEADER

#include <thrill/common/logger.hpp>
#include <thrill/data/serialization.hpp>

#include <algorithm>
#include <string>

namespace thrill {
namespace common {

/**
 * FastString is a fast implementation of a string, which is basically only
 * a char pointer and a length. The FastString is defined by the char array given
 * by those parameters. A copy assignment or copy constructor actually allocates
 * memory for the data. This allows both non-allocating quick references and persistent
 * storage of strings.
 */
class FastString
{
public:
    using iterator = const char*;

    /**
     * Default constructor for a FastString.
     * Doesn't do anything.
     */
    FastString() : size_(0) { }

    /**
     * Copy constructor for a new FastString. Actually allocates memory.
     * \param input Input FastString
     * \return Copy of input
     */
    FastString(const FastString& input) {
        char* begin = new char[input.size_];
        std::copy(input.data_, input.data_ + input.size_, begin);
        data_ = begin;
        size_ = input.size_;
        owns_data_ = true;
    }

    /**
     * Move constructor for a new FastString. Steals data ownership.
     */
    FastString(FastString&& other)
        : FastString(other.data_, other.size_, other.owns_data_) {
        other.owns_data_ = false;
    }

    /**
     * Destructor for a FastString. If it holds data, this data gets freed.
     */
    ~FastString() {
        if (owns_data_) {
            delete[] (data_);
        }
    }

    /**
     * Creates a new reference FastString, given a const char* and the size of the FastString.
     * \param data Pointer to start of data
     * \param size Size of data in bytes.
     * \return New FastString object.
     */
    static FastString Ref(const char* data, size_t size) {
        return FastString(data, size, false);
    }

    /**
     * Creates a new reference FastString, given a const iterator to a std::string
     * and the size of the FastString.
     * \param data Pointer to start of data
     * \param size Size of data in bytes.
     * \return New FastString object.
     */
    static FastString Ref(const std::string::const_iterator& data, size_t size) {
        return FastString(&(*data), size, false);
    }

    /**
     * Creates a new FastString and takes data ownership,
     * given a const char* and the size of the FastString.
     * \param data Pointer to start of data
     * \param size Size of data in bytes.
     * \return New FastString object.
     */
    static FastString Take(const char* data, size_t size) {
        return FastString(data, size, true);
    }

    /**
     * Creates a new FastString and copies it's data.
     * \param data Pointer to start of data
     * \param size Size of data in bytes.
     * \return New FastString object.
     */
    static FastString Copy(const char* data, size_t size) {
        char* mem = new char[size];
        std::copy(data, data + size, mem);
        return FastString(mem, size, true);
    }

    /**
     * Creates a new FastString and copies it's data.
     * \param input Input string, which the new FastString is a copy of
     * \return New FastString object.
     */
    static FastString Copy(const std::string& input) {
        return Copy(input.c_str(), input.size());
    }

    //! Returns a pointer to the start of the data.
    const char * Data() const {
        return data_;
    }

    //! Returns a pointer to the beginning of the data.
    iterator begin() const {
        return data_;
    }

    //! Returns a pointer beyond the end of the data.
    iterator end() const {
        return data_ + size_;
    }

    //! Returns the size of this FastString
    size_t Size() const {
        return size_;
    }

    /**
     * Copy assignment operator.
     * \param other copied FastString
     * \return reference to this FastString
     */
    FastString& operator = (const FastString& other) {
        if (owns_data_) delete[] (data_);
        char* mem = new char[other.size_];
        std::copy(other.data_, other.data_ + other.size_, mem);
        data_ = mem;
        size_ = other.size_;
        owns_data_ = true;
        return *this;
    }

    /**
     * Move assignment operator
     * \param other moved FastString
     * \return reference to this FastString
     */
    FastString& operator = (FastString&& other) {
        if (owns_data_) delete[] (data_);
        data_ = std::move(other.data_);
        size_ = other.Size();
        owns_data_ = other.owns_data_;
        other.owns_data_ = false;
        return *this;
    }

    /**
     * Equality operator to compare a FastString with an std::string
     * \param other Comparison string
     * \return true, if data is equal
     */
    bool operator == (const std::string& other) const {
        return size_ == other.size() &&
               std::equal(data_, data_ + size_, other.c_str());
    }

    /**
     * Inequality operator to compare a FastString with an std::string
     * \param other Comparison string
     * \return false, if data is equal
     */
    bool operator != (const std::string& other) const {
        return !(operator == (other));
    }

    /**
     * Equality operator to compare a FastString with another FastString
     * \param other Comparison FastString
     * \return true, if data is equal
     */
    bool operator == (const FastString& other) const {
        return size_ == other.size_ &&
               std::equal(data_, data_ + size_, other.data_);
    }

    /**
     * Inequality operator to compare a FastString with another FastString
     * \param other Comparison FastString
     * \return false, if data is equal
     */
    bool operator != (const FastString& other) const {
        return !(operator == (other));
    }

    /**
     * Make FastString ostreamable
     * \param os ostream
     * \param fs FastString to stream
     */
    friend std::ostream& operator << (std::ostream& os, const FastString& fs) {
        return os.write(fs.Data(), fs.Size());
    }

    /**
     * Returns the data of this FastString as an std::string
     * \return This FastString as an std::string
     */
    std::string ToString() const {
        return std::string(data_, size_);
    }

protected:
    /**
     * Internal constructor, which creates a new FastString and sets parameters
     * \param data Pointer to data
     * \param size Size of data in bytes
     * \param owns_data True, if this FastString has ownership of data
     */
    FastString(const char* data, size_t size, bool owns_data)
        : data_(data), size_(size), owns_data_(owns_data) { }

    //! Pointer to data
    const char* data_ = 0;
    //! Size of data
    size_t size_;
    //! True, if this FastString has ownership of data
    bool owns_data_ = false;
};

} // namespace common

namespace data {

template <typename Archive>
struct Serialization<Archive, common::FastString>
{
    static void Serialize(const common::FastString& fs, Archive& ar) {
        ar.PutVarint(fs.Size()).Append(fs.Data(), fs.Size());
    }

    static common::FastString Deserialize(Archive& ar) {
        uint64_t size = ar.GetVarint();
        char* outdata = new char[size];
        ar.Read(outdata, size);
        return common::FastString::Take(outdata, size);
    }

    static const bool   is_fixed_size = false;
    static const size_t fixed_size = 0;
};

} // namespace data
} // namespace thrill

namespace std {
template <>
struct hash<thrill::common::FastString>
{
    size_t operator () (const thrill::common::FastString& fs) const {
        // simple string hash taken from: http://www.cse.yorku.ca/~oz/hash.html
        size_t hash = 5381;
        for (const char* ctr = fs.begin(); ctr != fs.end(); ++ctr) {
            // hash * 33 + c
            hash = ((hash << 5) + hash) + *ctr;
        }
        return hash;
    }
};

} // namespace std

#endif // !THRILL_COMMON_FAST_STRING_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include "list.h"

using namespace std;
/* A linked list node */
struct node
{
 int data;
 struct node *next;
};
//typedef struct node node;
node *start =NULL;
/* ************************************************************
Function Name:populate
Return type:void
Arguments :void
Description:It fills the list with values provided
***************************************************************/
void list:: populate()
{
    int val;
    node *p;
    node *q;
    cout<<"Enter the Elements\n";
    p=NULL;

        while (size--)
    {
        cin>>val;

           if (p == NULL)
           {

            p=(struct node *) malloc(sizeof(struct node));
            p->data = val;
            p->next = NULL;
            start=p;

           }
                else
            {
            q=(struct node *) malloc(sizeof(struct node));
            q->data = val;
            q->next = NULL;
            p->next = q;
            p=p->next;
            }

    }
}
/* ************************************************************
Function Name:purging
Return type:void
Arguments :void
Description:compares the element with next element(s) and
                   deletes if same
***************************************************************/

void list::purging()
{
    node *x=start;
    node *y=start;

    while(x->next!=NULL){
           y=x->next;
        while(y->next!=NULL)
        {
	   if (x->data==y->data)
           {
              cout<< "inside if\n";
                x->next=y->next;
                y->next=NULL;
                free(y);
                y=x->next;
           }
             else{
              y=y->next;
          }

    }
    if(y->next==NULL){
    if (x->data==y->data) //if same then data
           {
                cout<< "inside if\n";
                x->next=NULL;
                free(y);
                return;
             }
    }
x=x->next;
}
}
/* ************************************************************
Function Name:display
Return type:void
Arguments :void
Description:Displays the values present in list at any instance
***************************************************************/

void list::display()
{
    node *start1=start;
   if(start1 == NULL)
    cout<<"\nNo data\n";
   else
   {
        cout<<"\nThe elements are: ";
        while(start1!=NULL)
        {
            printf(" %d ",start1->data);
            start1=start1->next;

        }
        cout<<"\n";
   }
}

void list::del(int i){
}

<commit_msg>Update linkedlist.cpp<commit_after>#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include "list.h"

using namespace std;
/* A linked list node */
struct node
{
 int data;
 struct node *next;
};
//typedef struct node node;
node *start =NULL;
/* ************************************************************
Function Name:populate
Return type:void
Arguments :void
Description:It fills the list with values provided
***************************************************************/
void list:: populate()
{
    int val;
    node *p;
    node *q;
    cout<<"Enter the Elements\n";
    p=NULL;

        while (size--)
    {
        cin>>val;

           if (p == NULL)
           {

            p=(struct node *) malloc(sizeof(struct node));
            p->data = val;
            p->next = NULL;
            start=p;

           }
                else
            {
            q=(struct node *) malloc(sizeof(struct node));
            q->data = val;
            q->next = NULL;
            p->next = q;
            p=p->next;
            }

    }
}
/* ************************************************************
Function Name:purging
Return type:void
Arguments :void
Description:compares the element with next element(s) and
                   deletes if same
***************************************************************/

void list::purging()
{
	//13  5  9  5  -13  2  3  -9  13  -9
    node *x=start;
    node *y=start;
    node *z=start;

    if(x->next!=NULL)
    {
    		cout<<"\ninside1: \n";

           		z=x->next;
      while (x->next!=NULL)
        {
        //cout<<"\ninside while1: \n";

	  cout<<"\nx:  "<<x->data<<" y:  "<< y->data <<" z:  "<< z->data;
	   if (x->data==z->data)
           {
              cout<<"\ndata same\n";
                if(z->next!=NULL) //MODIFIACTION 2
                {
                y->next=z->next;
                cout<<"\ndata deleting is:  \n"<<z->data<<endl;
                z->next=NULL;
                free(z);
                z=y->next;
                }
                else
                {
                cout<<"\n**data deleting is:  \n"<<z->data<<endl;
                y->next=NULL;
                z->next=NULL;
                free(z);
                x=x->next;
           	y=x;
           	if (y->next!=NULL)
          	z=y->next;
          	}
           }
             	else if(z->next!=NULL)
             	{

                           z=z->next;
                           y=y->next;
                           cout<<"\n**"<<endl;
                          // cout<<"\nz: "<< z->data <<" y:  "<< y->data;
          	}
          	else
          	{
          	cout<<"\n***\n"<<endl;
          	x=x->next;
          	y=x;
          	z=x->next;
          	}
    }
    /*if(y->next==NULL){
    if (x->data==y->data) //if same then data
           {
                cout<< "inside if\n";
                x->next=NULL;
                free(y);
                return;
             }
		x=x->next;
    }
*/
}
}

/* ************************************************************
Function Name:display
Return type:void
Arguments :void
Description:Displays the values present in list at any instance
***************************************************************/

void list::display()
{
    node *start1=start;
   if(start1 == NULL)
    cout<<"\nNo data\n";
   else
   {
        cout<<"\nThe elements are: ";
        while(start1!=NULL)
        {
            printf(" %d ",start1->data);
            start1=start1->next;

        }
        cout<<"\n";
   }
}

void list::del(int i){
}

<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LxQt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org, http://lxde.org/
 *
 * Copyright: 2010-2011 LxQt team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *   Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "lxqtmodman.h"
#include <LXQt/Settings>
#include <XdgAutoStart>
#include <XdgDirs>
#include <unistd.h>

#include <QDebug>
#include <QCoreApplication>
#include <QMessageBox>
#include <QSystemTrayIcon>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QDateTime>
#include "wmselectdialog.h"
#include "windowmanager.h"
#include <wordexp.h>

#include <KF5/KWindowSystem/KWindowSystem>
#include <KF5/KWindowSystem/netwm.h>

#include <QX11Info>

#define MAX_CRASHES_PER_APP 5

using namespace LxQt;

/**
 * @brief the constructor, needs a valid modules.conf
 */
LxQtModuleManager::LxQtModuleManager(const QString & windowManager, QObject* parent)
    : QObject(parent),
      mWindowManager(windowManager),
      mWmProcess(new QProcess(this)),
      mThemeWatcher(new QFileSystemWatcher(this)),
      mWmStarted(false),
      mTrayStarted(false),
      mWaitLoop(NULL)
{
    connect(mThemeWatcher, SIGNAL(directoryChanged(QString)), SLOT(themeFolderChanged(QString)));
    connect(LxQt::Settings::globalSettings(), SIGNAL(lxqtThemeChanged()), SLOT(themeChanged()));

    qApp->installNativeEventFilter(this);
}

void LxQtModuleManager::startup(LxQt::Settings& s)
{
    // The lxqt-confupdate can update the settings of the WM, so run it first.
    startConfUpdate();

    // Start window manager
    startWm(&s);

    startAutostartApps();

    QStringList paths;
    paths << XdgDirs::dataHome(false);
    paths << XdgDirs::dataDirs();

    foreach(QString path, paths)
    {
        QFileInfo fi(QString("%1/lxqt/themes").arg(path));
        if (fi.exists())
            mThemeWatcher->addPath(fi.absoluteFilePath());
    }

    themeChanged();
}

void LxQtModuleManager::startAutostartApps()
{
    // XDG autostart
    XdgDesktopFileList fileList = XdgAutoStart::desktopFileList();
    QList<XdgDesktopFile*> trayApps;
    for (XdgDesktopFileList::iterator i = fileList.begin(); i != fileList.end(); ++i)
    {
        if (i->value("X-LXQt-Need-Tray", false).toBool())
            trayApps.append(&(*i));
        else
        {
            startProcess(*i);
            qDebug() << "start" << i->fileName();
        }
    }

    if (!trayApps.isEmpty())
    {
        mTrayStarted = QSystemTrayIcon::isSystemTrayAvailable();
        if(!mTrayStarted)
        {
            QEventLoop waitLoop;
            mWaitLoop = &waitLoop;
            // add a timeout to avoid infinite blocking if a WM fail to execute.
            QTimer::singleShot(60 * 1000, &waitLoop, SLOT(quit()));
            waitLoop.exec();
            mWaitLoop = NULL;
        }
        foreach (XdgDesktopFile* f, trayApps)
        {
            qDebug() << "start tray app" << f->fileName();
            startProcess(*f);
        }
    }
}

void LxQtModuleManager::themeFolderChanged(const QString& /*path*/)
{
    QString newTheme;
    if (!QFileInfo(mCurrentThemePath).exists())
    {
        const QList<LxQtTheme> &allThemes = lxqtTheme.allThemes();
        if (!allThemes.isEmpty())
            newTheme = allThemes[0].name();
        else
            return;
    }
    else
        newTheme = lxqtTheme.currentTheme().name();

    LxQt::Settings settings("lxqt");
    if (newTheme == settings.value("theme"))
    {
        // force the same theme to be updated
        settings.setValue("__theme_updated__", QDateTime::currentMSecsSinceEpoch());
    }
    else
        settings.setValue("theme", newTheme);

    sync();
}

void LxQtModuleManager::themeChanged()
{
    if (!mCurrentThemePath.isEmpty())
        mThemeWatcher->removePath(mCurrentThemePath);

    if (lxqtTheme.currentTheme().isValid())
    {
        mCurrentThemePath = lxqtTheme.currentTheme().path();
        mThemeWatcher->addPath(mCurrentThemePath);
    }
}

void LxQtModuleManager::startWm(LxQt::Settings *settings)
{
    // If the WM is active do not run WM.
    NETRootInfo info(QX11Info::connection(), NET::Supported);
    if (info.isSupported(NET::SupportingWMCheck))
        return;

    if (mWindowManager.isEmpty())
    {
        mWindowManager = settings->value("window_manager").toString();
    }

    // If previuos WM was removed, we show dialog.
    if (mWindowManager.isEmpty() || ! findProgram(mWindowManager.split(' ')[0]))
    {
        mWindowManager = showWmSelectDialog();
        settings->setValue("window_manager", mWindowManager);
        settings->sync();
    }

    mWmProcess->start(mWindowManager);
    // other autostart apps will be handled after the WM becomes available

    // Wait until the WM loads
    QEventLoop waitLoop;
    mWaitLoop = &waitLoop;
    // add a timeout to avoid infinite blocking if a WM fail to execute.
    QTimer::singleShot(30 * 1000, &waitLoop, SLOT(quit()));
    waitLoop.exec();
    mWaitLoop = NULL;
    // FIXME: blocking is a bad idea. We need to start as many apps as possible and
    //         only wait for the start of WM when it's absolutely needed.
    //         Maybe we can add a X-Wait-WM=true key in the desktop entry file?
}

void LxQtModuleManager::startProcess(const XdgDesktopFile& file)
{
    if (!file.value("X-LXQt-Module", false).toBool())
    {
        file.startDetached();
        return;
    }
    QStringList args = file.expandExecString();
    if (args.isEmpty())
    {
        qWarning() << "Wrong desktop file" << file.fileName();
        return;
    }
    LxQtModule* proc = new LxQtModule(file, this);
    connect(proc, SIGNAL(moduleStateChanged(QString,bool)), this, SIGNAL(moduleStateChanged(QString,bool)));
    proc->start();

    QString name = QFileInfo(file.fileName()).fileName();
    mNameMap[name] = proc;

    connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)),
            this, SLOT(restartModules(int, QProcess::ExitStatus)));
}

void LxQtModuleManager::startProcess(const QString& name)
{
    if (!mNameMap.contains(name))
    {
        foreach (const XdgDesktopFile& file, XdgAutoStart::desktopFileList(false))
        {
            if (QFileInfo(file.fileName()).fileName() == name)
            {
                startProcess(file);
                return;
            }
        }
    }
}

void LxQtModuleManager::stopProcess(const QString& name)
{
    if (mNameMap.contains(name))
        mNameMap[name]->terminate();
}

QStringList LxQtModuleManager::listModules() const
{
    return QStringList(mNameMap.keys());
}

void LxQtModuleManager::startConfUpdate()
{
    XdgDesktopFile desktop(XdgDesktopFile::ApplicationType, ":lxqt-confupdate", "lxqt-confupdate --watch");
    desktop.setValue("Name", "LXQt config updater");
    desktop.setValue("X-LXQt-Module", true);
    startProcess(desktop);
}

void LxQtModuleManager::restartModules(int exitCode, QProcess::ExitStatus exitStatus)
{
    LxQtModule* proc = qobject_cast<LxQtModule*>(sender());
    Q_ASSERT(proc);

    if (!proc->isTerminating())
    {
        QString procName = proc->file.name();
        switch (exitStatus)
        {
            case QProcess::NormalExit:
                qDebug() << "Process" << procName << "(" << proc << ") exited correctly.";
                break;
            case QProcess::CrashExit:
            {
                qDebug() << "Process" << procName << "(" << proc << ") has to be restarted";
                time_t now = time(NULL);
                mCrashReport[proc].prepend(now);
                while (now - mCrashReport[proc].back() > 60)
                    mCrashReport[proc].pop_back();
                if (mCrashReport[proc].length() >= MAX_CRASHES_PER_APP)
                {
                    QMessageBox::warning(0, tr("Crash Report"),
                                        tr("<b>%1</b> crashed too many times. Its autorestart has been disabled until next login.").arg(procName));
                }
                else
                {
                    proc->start();
                    return;
                }
                break;
            }
        }
    }
    mNameMap.remove(proc->fileName);
    proc->deleteLater();
}

LxQtModuleManager::~LxQtModuleManager()
{
    qApp->removeNativeEventFilter(this);
    qDeleteAll(mNameMap);
    delete mWmProcess;
}

/**
* @brief this logs us out by terminating our session
**/
void LxQtModuleManager::logout()
{
    // modules
    ModulesMapIterator i(mNameMap);
    while (i.hasNext())
    {
        i.next();
        qDebug() << "Module logout" << i.key();
        LxQtModule* p = i.value();
        p->terminate();
    }
    i.toFront();
    while (i.hasNext())
    {
        i.next();
        LxQtModule* p = i.value();
        if (p->state() != QProcess::NotRunning && !p->waitForFinished())
        {
            qWarning() << QString("Module '%1' won't terminate ... killing.").arg(i.key());
            p->kill();
        }
    }

    mWmProcess->terminate();
    if (mWmProcess->state() != QProcess::NotRunning && !mWmProcess->waitForFinished())
    {
        qWarning() << QString("Window Manager won't terminate ... killing.");
        mWmProcess->kill();
    }

    QCoreApplication::exit(0);
}

QString LxQtModuleManager::showWmSelectDialog()
{
    WindowManagerList availableWM = getWindowManagerList(true);
    if (availableWM.count() == 1)
        return availableWM.at(0).command;

    WmSelectDialog dlg(availableWM);
    dlg.exec();
    return dlg.windowManager();
}

void LxQtModuleManager::resetCrashReport()
{
    mCrashReport.clear();
}

bool LxQtModuleManager::nativeEventFilter(const QByteArray & eventType, void * message, long * result)
{
    if (eventType != "xcb_generic_event_t") // We only want to handle XCB events
        return false;

    if(!mWmStarted && mWaitLoop)
    {
        NETRootInfo info(QX11Info::connection(), NET::Supported);
        NET::Properties prop = info.event(reinterpret_cast<xcb_generic_event_t*>(message));

        if (prop & NET::SupportingWMCheck)
        {
            qDebug() << "Window Manager started";
            mWmStarted = true;
            if (mWaitLoop->isRunning())
                mWaitLoop->exit();
        }
    }

    if (!mTrayStarted && QSystemTrayIcon::isSystemTrayAvailable() && mWaitLoop)
    {
        qDebug() << "System Tray started";
        mTrayStarted = true;
        if (mWaitLoop->isRunning())
            mWaitLoop->exit();
    }

    return false;
}

void lxqt_setenv(const char *env, const QByteArray &value)
{
    wordexp_t p;
    wordexp(value, &p, 0);
    if (p.we_wordc == 1)
    {

        qDebug() << "Environment variable" << env << "=" << p.we_wordv[0];
        qputenv(env, p.we_wordv[0]);
    }
    else
    {
        qWarning() << "Error expanding environment variable" << env << "=" << value;
        qputenv(env, value);
    }
     wordfree(&p);
}

void lxqt_setenv_prepend(const char *env, const QByteArray &value, const QByteArray &separator)
{
    QByteArray orig(qgetenv(env));
    orig = orig.prepend(separator);
    orig = orig.prepend(value);
    qDebug() << "Setting special" << env << " variable:" << orig;
    lxqt_setenv(env, orig);
}

LxQtModule::LxQtModule(const XdgDesktopFile& file, QObject* parent) :
    QProcess(parent),
    file(file),
    fileName(QFileInfo(file.fileName()).fileName()),
    mIsTerminating(false)
{
    connect(this, SIGNAL(stateChanged(QProcess::ProcessState)), SLOT(updateState(QProcess::ProcessState)));
}

void LxQtModule::start()
{
    mIsTerminating = false;
    QStringList args = file.expandExecString();
    QString command = args.takeFirst();
    QProcess::start(command, args);
}

void LxQtModule::terminate()
{
    mIsTerminating = true;
    QProcess::terminate();
}

bool LxQtModule::isTerminating()
{
    return mIsTerminating;
}

void LxQtModule::updateState(QProcess::ProcessState newState)
{
    if (newState != QProcess::Starting)
        emit moduleStateChanged(fileName, (newState == QProcess::Running));
}
<commit_msg>Better window manager detection<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LxQt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org, http://lxde.org/
 *
 * Copyright: 2010-2011 LxQt team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *   Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "lxqtmodman.h"
#include <LXQt/Settings>
#include <XdgAutoStart>
#include <XdgDirs>
#include <unistd.h>

#include <QDebug>
#include <QCoreApplication>
#include <QMessageBox>
#include <QSystemTrayIcon>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QDateTime>
#include "wmselectdialog.h"
#include "windowmanager.h"
#include <wordexp.h>

#include <KF5/KWindowSystem/KWindowSystem>
#include <KF5/KWindowSystem/netwm.h>

#include <QX11Info>

#define MAX_CRASHES_PER_APP 5

using namespace LxQt;

/**
 * @brief the constructor, needs a valid modules.conf
 */
LxQtModuleManager::LxQtModuleManager(const QString & windowManager, QObject* parent)
    : QObject(parent),
      mWindowManager(windowManager),
      mWmProcess(new QProcess(this)),
      mThemeWatcher(new QFileSystemWatcher(this)),
      mWmStarted(false),
      mTrayStarted(false),
      mWaitLoop(NULL)
{
    connect(mThemeWatcher, SIGNAL(directoryChanged(QString)), SLOT(themeFolderChanged(QString)));
    connect(LxQt::Settings::globalSettings(), SIGNAL(lxqtThemeChanged()), SLOT(themeChanged()));

    qApp->installNativeEventFilter(this);
}

void LxQtModuleManager::startup(LxQt::Settings& s)
{
    // The lxqt-confupdate can update the settings of the WM, so run it first.
    startConfUpdate();

    // Start window manager
    startWm(&s);

    startAutostartApps();

    QStringList paths;
    paths << XdgDirs::dataHome(false);
    paths << XdgDirs::dataDirs();

    foreach(QString path, paths)
    {
        QFileInfo fi(QString("%1/lxqt/themes").arg(path));
        if (fi.exists())
            mThemeWatcher->addPath(fi.absoluteFilePath());
    }

    themeChanged();
}

void LxQtModuleManager::startAutostartApps()
{
    // XDG autostart
    XdgDesktopFileList fileList = XdgAutoStart::desktopFileList();
    QList<XdgDesktopFile*> trayApps;
    for (XdgDesktopFileList::iterator i = fileList.begin(); i != fileList.end(); ++i)
    {
        if (i->value("X-LXQt-Need-Tray", false).toBool())
            trayApps.append(&(*i));
        else
        {
            startProcess(*i);
            qDebug() << "start" << i->fileName();
        }
    }

    if (!trayApps.isEmpty())
    {
        mTrayStarted = QSystemTrayIcon::isSystemTrayAvailable();
        if(!mTrayStarted)
        {
            QEventLoop waitLoop;
            mWaitLoop = &waitLoop;
            // add a timeout to avoid infinite blocking if a WM fail to execute.
            QTimer::singleShot(60 * 1000, &waitLoop, SLOT(quit()));
            waitLoop.exec();
            mWaitLoop = NULL;
        }
        foreach (XdgDesktopFile* f, trayApps)
        {
            qDebug() << "start tray app" << f->fileName();
            startProcess(*f);
        }
    }
}

void LxQtModuleManager::themeFolderChanged(const QString& /*path*/)
{
    QString newTheme;
    if (!QFileInfo(mCurrentThemePath).exists())
    {
        const QList<LxQtTheme> &allThemes = lxqtTheme.allThemes();
        if (!allThemes.isEmpty())
            newTheme = allThemes[0].name();
        else
            return;
    }
    else
        newTheme = lxqtTheme.currentTheme().name();

    LxQt::Settings settings("lxqt");
    if (newTheme == settings.value("theme"))
    {
        // force the same theme to be updated
        settings.setValue("__theme_updated__", QDateTime::currentMSecsSinceEpoch());
    }
    else
        settings.setValue("theme", newTheme);

    sync();
}

void LxQtModuleManager::themeChanged()
{
    if (!mCurrentThemePath.isEmpty())
        mThemeWatcher->removePath(mCurrentThemePath);

    if (lxqtTheme.currentTheme().isValid())
    {
        mCurrentThemePath = lxqtTheme.currentTheme().path();
        mThemeWatcher->addPath(mCurrentThemePath);
    }
}

void LxQtModuleManager::startWm(LxQt::Settings *settings)
{
    // if the WM is active do not run WM.
    // all window managers must set their name according to the spec
    if (!QString(NETRootInfo(QX11Info::connection(), NET::SupportingWMCheck).wmName()).isEmpty())
    {
        mWmStarted = true;
        return;
    }

    if (mWindowManager.isEmpty())
    {
        mWindowManager = settings->value("window_manager").toString();
    }

    // If previuos WM was removed, we show dialog.
    if (mWindowManager.isEmpty() || ! findProgram(mWindowManager.split(' ')[0]))
    {
        mWindowManager = showWmSelectDialog();
        settings->setValue("window_manager", mWindowManager);
        settings->sync();
    }

    mWmProcess->start(mWindowManager);
    // other autostart apps will be handled after the WM becomes available

    // Wait until the WM loads
    QEventLoop waitLoop;
    mWaitLoop = &waitLoop;
    // add a timeout to avoid infinite blocking if a WM fail to execute.
    QTimer::singleShot(30 * 1000, &waitLoop, SLOT(quit()));
    waitLoop.exec();
    mWaitLoop = NULL;
    // FIXME: blocking is a bad idea. We need to start as many apps as possible and
    //         only wait for the start of WM when it's absolutely needed.
    //         Maybe we can add a X-Wait-WM=true key in the desktop entry file?
}

void LxQtModuleManager::startProcess(const XdgDesktopFile& file)
{
    if (!file.value("X-LXQt-Module", false).toBool())
    {
        file.startDetached();
        return;
    }
    QStringList args = file.expandExecString();
    if (args.isEmpty())
    {
        qWarning() << "Wrong desktop file" << file.fileName();
        return;
    }
    LxQtModule* proc = new LxQtModule(file, this);
    connect(proc, SIGNAL(moduleStateChanged(QString,bool)), this, SIGNAL(moduleStateChanged(QString,bool)));
    proc->start();

    QString name = QFileInfo(file.fileName()).fileName();
    mNameMap[name] = proc;

    connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)),
            this, SLOT(restartModules(int, QProcess::ExitStatus)));
}

void LxQtModuleManager::startProcess(const QString& name)
{
    if (!mNameMap.contains(name))
    {
        foreach (const XdgDesktopFile& file, XdgAutoStart::desktopFileList(false))
        {
            if (QFileInfo(file.fileName()).fileName() == name)
            {
                startProcess(file);
                return;
            }
        }
    }
}

void LxQtModuleManager::stopProcess(const QString& name)
{
    if (mNameMap.contains(name))
        mNameMap[name]->terminate();
}

QStringList LxQtModuleManager::listModules() const
{
    return QStringList(mNameMap.keys());
}

void LxQtModuleManager::startConfUpdate()
{
    XdgDesktopFile desktop(XdgDesktopFile::ApplicationType, ":lxqt-confupdate", "lxqt-confupdate --watch");
    desktop.setValue("Name", "LXQt config updater");
    desktop.setValue("X-LXQt-Module", true);
    startProcess(desktop);
}

void LxQtModuleManager::restartModules(int exitCode, QProcess::ExitStatus exitStatus)
{
    LxQtModule* proc = qobject_cast<LxQtModule*>(sender());
    Q_ASSERT(proc);

    if (!proc->isTerminating())
    {
        QString procName = proc->file.name();
        switch (exitStatus)
        {
            case QProcess::NormalExit:
                qDebug() << "Process" << procName << "(" << proc << ") exited correctly.";
                break;
            case QProcess::CrashExit:
            {
                qDebug() << "Process" << procName << "(" << proc << ") has to be restarted";
                time_t now = time(NULL);
                mCrashReport[proc].prepend(now);
                while (now - mCrashReport[proc].back() > 60)
                    mCrashReport[proc].pop_back();
                if (mCrashReport[proc].length() >= MAX_CRASHES_PER_APP)
                {
                    QMessageBox::warning(0, tr("Crash Report"),
                                        tr("<b>%1</b> crashed too many times. Its autorestart has been disabled until next login.").arg(procName));
                }
                else
                {
                    proc->start();
                    return;
                }
                break;
            }
        }
    }
    mNameMap.remove(proc->fileName);
    proc->deleteLater();
}

LxQtModuleManager::~LxQtModuleManager()
{
    qApp->removeNativeEventFilter(this);
    qDeleteAll(mNameMap);
    delete mWmProcess;
}

/**
* @brief this logs us out by terminating our session
**/
void LxQtModuleManager::logout()
{
    // modules
    ModulesMapIterator i(mNameMap);
    while (i.hasNext())
    {
        i.next();
        qDebug() << "Module logout" << i.key();
        LxQtModule* p = i.value();
        p->terminate();
    }
    i.toFront();
    while (i.hasNext())
    {
        i.next();
        LxQtModule* p = i.value();
        if (p->state() != QProcess::NotRunning && !p->waitForFinished())
        {
            qWarning() << QString("Module '%1' won't terminate ... killing.").arg(i.key());
            p->kill();
        }
    }

    mWmProcess->terminate();
    if (mWmProcess->state() != QProcess::NotRunning && !mWmProcess->waitForFinished())
    {
        qWarning() << QString("Window Manager won't terminate ... killing.");
        mWmProcess->kill();
    }

    QCoreApplication::exit(0);
}

QString LxQtModuleManager::showWmSelectDialog()
{
    WindowManagerList availableWM = getWindowManagerList(true);
    if (availableWM.count() == 1)
        return availableWM.at(0).command;

    WmSelectDialog dlg(availableWM);
    dlg.exec();
    return dlg.windowManager();
}

void LxQtModuleManager::resetCrashReport()
{
    mCrashReport.clear();
}

bool LxQtModuleManager::nativeEventFilter(const QByteArray & eventType, void * message, long * result)
{
    if (eventType != "xcb_generic_event_t") // We only want to handle XCB events
        return false;

    if(!mWmStarted && mWaitLoop)
    {
        // all window managers must set their name according to the spec
        if (!QString(NETRootInfo(QX11Info::connection(), NET::SupportingWMCheck).wmName()).isEmpty())
        {
            qDebug() << "Window Manager started";
            mWmStarted = true;
            if (mWaitLoop->isRunning())
                mWaitLoop->exit();
        }
    }

    if (!mTrayStarted && QSystemTrayIcon::isSystemTrayAvailable() && mWaitLoop)
    {
        qDebug() << "System Tray started";
        mTrayStarted = true;
        if (mWaitLoop->isRunning())
            mWaitLoop->exit();

        // window manager and system tray have started
        qApp->removeNativeEventFilter(this);
    }

    return false;
}

void lxqt_setenv(const char *env, const QByteArray &value)
{
    wordexp_t p;
    wordexp(value, &p, 0);
    if (p.we_wordc == 1)
    {

        qDebug() << "Environment variable" << env << "=" << p.we_wordv[0];
        qputenv(env, p.we_wordv[0]);
    }
    else
    {
        qWarning() << "Error expanding environment variable" << env << "=" << value;
        qputenv(env, value);
    }
     wordfree(&p);
}

void lxqt_setenv_prepend(const char *env, const QByteArray &value, const QByteArray &separator)
{
    QByteArray orig(qgetenv(env));
    orig = orig.prepend(separator);
    orig = orig.prepend(value);
    qDebug() << "Setting special" << env << " variable:" << orig;
    lxqt_setenv(env, orig);
}

LxQtModule::LxQtModule(const XdgDesktopFile& file, QObject* parent) :
    QProcess(parent),
    file(file),
    fileName(QFileInfo(file.fileName()).fileName()),
    mIsTerminating(false)
{
    connect(this, SIGNAL(stateChanged(QProcess::ProcessState)), SLOT(updateState(QProcess::ProcessState)));
}

void LxQtModule::start()
{
    mIsTerminating = false;
    QStringList args = file.expandExecString();
    QString command = args.takeFirst();
    QProcess::start(command, args);
}

void LxQtModule::terminate()
{
    mIsTerminating = true;
    QProcess::terminate();
}

bool LxQtModule::isTerminating()
{
    return mIsTerminating;
}

void LxQtModule::updateState(QProcess::ProcessState newState)
{
    if (newState != QProcess::Starting)
        emit moduleStateChanged(fileName, (newState == QProcess::Running));
}
<|endoftext|>