<commit_before>//===- ReadConst.cpp - Code to constants and constant pools ---------------===//
//
// This file implements functionality to deserialize constants and entire
// constant pools.
//
// Note that this library should be as fast as possible, reentrant, and
// threadsafe!!
//
//===----------------------------------------------------------------------===//

#include "ReaderInternals.h"
#include "llvm/Module.h"
#include "llvm/Constants.h"
#include "llvm/GlobalVariable.h"
#include <algorithm>
#include <iostream>

using std::make_pair;

const Type *BytecodeParser::parseTypeConstant(const uchar *&Buf,
					      const uchar *EndBuf) {
  unsigned PrimType;
  if (read_vbr(Buf, EndBuf, PrimType)) return failure<const Type*>(0);

  const Type *Val = 0;
  if ((Val = Type::getPrimitiveType((Type::PrimitiveID)PrimType)))
    return Val;

  switch (PrimType) {
  case Type::FunctionTyID: {
    unsigned Typ;
    if (read_vbr(Buf, EndBuf, Typ)) return failure(Val);
    const Type *RetType = getType(Typ);
    if (RetType == 0) return failure(Val);

    unsigned NumParams;
    if (read_vbr(Buf, EndBuf, NumParams)) return failure(Val);

    std::vector<const Type*> Params;
    while (NumParams--) {
      if (read_vbr(Buf, EndBuf, Typ)) return failure(Val);
      const Type *Ty = getType(Typ);
      if (Ty == 0) return failure(Val);
      Params.push_back(Ty);
    }

    bool isVarArg = Params.size() && Params.back() == Type::VoidTy;
    if (isVarArg) Params.pop_back();

    return FunctionType::get(RetType, Params, isVarArg);
  }
  case Type::ArrayTyID: {
    unsigned ElTyp;
    if (read_vbr(Buf, EndBuf, ElTyp)) return failure(Val);
    const Type *ElementType = getType(ElTyp);
    if (ElementType == 0) return failure(Val);

    unsigned NumElements;
    if (read_vbr(Buf, EndBuf, NumElements)) return failure(Val);

    BCR_TRACE(5, "Array Type Constant #" << ElTyp << " size="
              << NumElements << "\n");
    return ArrayType::get(ElementType, NumElements);
  }
  case Type::StructTyID: {
    unsigned Typ;
    std::vector<const Type*> Elements;

    if (read_vbr(Buf, EndBuf, Typ)) return failure(Val);
    while (Typ) {         // List is terminated by void/0 typeid
      const Type *Ty = getType(Typ);
      if (Ty == 0) return failure(Val);
      Elements.push_back(Ty);

      if (read_vbr(Buf, EndBuf, Typ)) return failure(Val);
    }

    return StructType::get(Elements);
  }
  case Type::PointerTyID: {
    unsigned ElTyp;
    if (read_vbr(Buf, EndBuf, ElTyp)) return failure(Val);
    BCR_TRACE(5, "Pointer Type Constant #" << (ElTyp-14) << "\n");
    const Type *ElementType = getType(ElTyp);
    if (ElementType == 0) return failure(Val);
    return PointerType::get(ElementType);
  }

  case Type::OpaqueTyID: {
    return OpaqueType::get();
  }

  default:
    std::cerr << __FILE__ << ":" << __LINE__
	      << ": Don't know how to deserialize"
	      << " primitive Type " << PrimType << "\n";
    return failure(Val);
  }
}

// refineAbstractType - The callback method is invoked when one of the
// elements of TypeValues becomes more concrete...
//
void BytecodeParser::refineAbstractType(const DerivedType *OldType,
					const Type *NewType) {
  if (OldType == NewType &&
      OldType->isAbstract()) return;  // Type is modified, but same

  TypeValuesListTy::iterator I = find(MethodTypeValues.begin(),
				      MethodTypeValues.end(), OldType);
  if (I == MethodTypeValues.end()) {
    I = find(ModuleTypeValues.begin(), ModuleTypeValues.end(), OldType);
    assert(I != ModuleTypeValues.end() &&
	   "Can't refine a type I don't know about!");
  }

  if (OldType == NewType) {
    assert(!OldType->isAbstract());
    I->removeUserFromConcrete();
  } else {
    *I = NewType;  // Update to point to new, more refined type.
  }
}

// parseTypeConstants - We have to use this wierd code to handle recursive
// types.  We know that recursive types will only reference the current slab of
// values in the type plane, but they can forward reference types before they
// have been read.  For example, Type #0 might be '{ Ty#1 }' and Type #1 might
// be 'Ty#0*'.  When reading Type #0, type number one doesn't exist.  To fix
// this ugly problem, we pesimistically insert an opaque type for each type we
// are about to read.  This means that forward references will resolve to
// something and when we reread the type later, we can replace the opaque type
// with a new resolved concrete type.
//
void debug_type_tables();
bool BytecodeParser::parseTypeConstants(const uchar *&Buf, const uchar *EndBuf,
					TypeValuesListTy &Tab,
					unsigned NumEntries) {
  assert(Tab.size() == 0 && "should not have read type constants in before!");

  // Insert a bunch of opaque types to be resolved later...
  for (unsigned i = 0; i < NumEntries; ++i)
    Tab.push_back(PATypeHandle<Type>(OpaqueType::get(), this));

  // Loop through reading all of the types.  Forward types will make use of the
  // opaque types just inserted.
  //
  for (unsigned i = 0; i < NumEntries; ++i) {
    const Type *NewTy = parseTypeConstant(Buf, EndBuf), *OldTy = Tab[i].get();
    if (NewTy == 0) return failure(true);
    BCR_TRACE(4, "#" << i << ": Read Type Constant: '" << NewTy <<
              "' Replacing: " << OldTy << "\n");

    // Don't insertValue the new type... instead we want to replace the opaque
    // type with the new concrete value...
    //

    // Refine the abstract type to the new type.  This causes all uses of the
    // abstract type to use the newty.  This also will cause the opaque type
    // to be deleted...
    //
    ((DerivedType*)Tab[i].get())->refineAbstractTypeTo(NewTy);

    // This should have replace the old opaque type with the new type in the
    // value table... or with a preexisting type that was already in the system
    assert(Tab[i] != OldTy && "refineAbstractType didn't work!");
  }

  BCR_TRACE(5, "Resulting types:\n");
  for (unsigned i = 0; i < NumEntries; ++i) {
    BCR_TRACE(5, (void*)Tab[i].get() << " - " << Tab[i].get() << "\n");
  }
  debug_type_tables();
  return false;
}

bool BytecodeParser::parseConstantValue(const uchar *&Buf, const uchar *EndBuf,
                                        const Type *Ty, Constant *&V) {
  switch (Ty->getPrimitiveID()) {
  case Type::BoolTyID: {
    unsigned Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    if (Val != 0 && Val != 1) return failure(true);
    V = ConstantBool::get(Val == 1);
    break;
  }

  case Type::UByteTyID:   // Unsigned integer types...
  case Type::UShortTyID:
  case Type::UIntTyID: {
    unsigned Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    if (!ConstantUInt::isValueValidForType(Ty, Val)) return failure(true);
    V = ConstantUInt::get(Ty, Val);
    break;
  }

  case Type::ULongTyID: {
    uint64_t Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    V = ConstantUInt::get(Ty, Val);
    break;
  }

  case Type::SByteTyID:   // Unsigned integer types...
  case Type::ShortTyID:
  case Type::IntTyID: {
    int Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    if (!ConstantSInt::isValueValidForType(Ty, Val)) return failure(true);
    V = ConstantSInt::get(Ty, Val);
    break;
  }

  case Type::LongTyID: {
    int64_t Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    V = ConstantSInt::get(Ty, Val);
    break;
  }

  case Type::FloatTyID: {
    float F;
    if (input_data(Buf, EndBuf, &F, &F+1)) return failure(true);
    V = ConstantFP::get(Ty, F);
    break;
  }

  case Type::DoubleTyID: {
    double Val;
    if (input_data(Buf, EndBuf, &Val, &Val+1)) return failure(true);
    V = ConstantFP::get(Ty, Val);
    break;
  }

  case Type::TypeTyID:
    assert(0 && "Type constants should be handled seperately!!!");
    abort();

  case Type::ArrayTyID: {
    const ArrayType *AT = cast<const ArrayType>(Ty);
    unsigned NumElements = AT->getNumElements();

    std::vector<Constant*> Elements;
    while (NumElements--) {   // Read all of the elements of the constant.
      unsigned Slot;
      if (read_vbr(Buf, EndBuf, Slot)) return failure(true);
      Value *V = getValue(AT->getElementType(), Slot, false);
      if (!V || !isa<Constant>(V)) return failure(true);
      Elements.push_back(cast<Constant>(V));
    }
    V = ConstantArray::get(AT, Elements);
    break;
  }

  case Type::StructTyID: {
    const StructType *ST = cast<StructType>(Ty);
    const StructType::ElementTypes &ET = ST->getElementTypes();

    std::vector<Constant *> Elements;
    for (unsigned i = 0; i < ET.size(); ++i) {
      unsigned Slot;
      if (read_vbr(Buf, EndBuf, Slot)) return failure(true);
      Value *V = getValue(ET[i], Slot, false);
      if (!V || !isa<Constant>(V))
	return failure(true);
      Elements.push_back(cast<Constant>(V));
    }

    V = ConstantStruct::get(ST, Elements);
    break;
  }

  case Type::PointerTyID: {
    const PointerType *PT = cast<const PointerType>(Ty);
    unsigned SubClass;
    if (read_vbr(Buf, EndBuf, SubClass)) return failure(true);
    switch (SubClass) {
    case 0:    // ConstantPointerNull value...
      V = ConstantPointerNull::get(PT);
      break;

    case 1: {  // ConstantPointerRef value...
      unsigned Slot;
      if (read_vbr(Buf, EndBuf, Slot)) return failure(true);
      BCR_TRACE(4, "CPPR: Type: '" << Ty << "'  slot: " << Slot << "\n");

      // Check to see if we have already read this global variable yet...
      Value *Val = getValue(PT, Slot, false);
      GlobalValue *GV;
      if (Val) {
	if (!(GV = dyn_cast<GlobalValue>(Val))) return failure(true);
	BCR_TRACE(5, "Value Found in ValueTable!\n");
      } else {         // Nope... see if we have previously forward ref'd it
	GlobalRefsType::iterator I = GlobalRefs.find(make_pair(PT, Slot));
	if (I != GlobalRefs.end()) {
	  BCR_TRACE(5, "Previous forward ref found!\n");
	  GV = I->second;
	} else {
	  BCR_TRACE(5, "Creating new forward ref variable!\n");

	  // Create a placeholder for the global variable reference...
	  GlobalVariable *GVar =
	    new GlobalVariable(PT->getElementType(), false, true);

	  // Keep track of the fact that we have a forward ref to recycle it
	  GlobalRefs.insert(make_pair(make_pair(PT, Slot), GVar));

	  // Must temporarily push this value into the module table...
	  TheModule->getGlobalList().push_back(GVar);
	  GV = GVar;
	}
      }

      V = ConstantPointerRef::get(GV);
      break;
    }
    default:
      BCR_TRACE(5, "UNKNOWN Pointer Constant Type!\n");
      return failure(true);
    }
    break;
  }

  default:
    std::cerr << __FILE__ << ":" << __LINE__
	      << ": Don't know how to deserialize constant value of type '"
	      << Ty->getName() << "'\n";
    return failure(true);
  }

  return false;
}

bool BytecodeParser::ParseConstantPool(const uchar *&Buf, const uchar *EndBuf,
				       ValueTable &Tab,
				       TypeValuesListTy &TypeTab) {
  while (Buf < EndBuf) {
    unsigned NumEntries, Typ;

    if (read_vbr(Buf, EndBuf, NumEntries) ||
        read_vbr(Buf, EndBuf, Typ)) return failure(true);
    const Type *Ty = getType(Typ);
    if (Ty == 0) return failure(true);
    BCR_TRACE(3, "Type: '" << Ty << "'  NumEntries: " << NumEntries << "\n");

    if (Typ == Type::TypeTyID) {
      if (parseTypeConstants(Buf, EndBuf, TypeTab, NumEntries)) return true;
    } else {
      for (unsigned i = 0; i < NumEntries; ++i) {
	Constant *I;
	if (parseConstantValue(Buf, EndBuf, Ty, I)) return failure(true);
	BCR_TRACE(4, "Read Constant: '" << I << "'\n");
	if (insertValue(I, Tab) == -1) return failure(true);
      }
    }
  }

  if (Buf > EndBuf) return failure(true);
  return false;
}
<commit_msg>Convert tabs to spaces<commit_after>//===- ReadConst.cpp - Code to constants and constant pools ---------------===//
//
// This file implements functionality to deserialize constants and entire
// constant pools.
//
// Note that this library should be as fast as possible, reentrant, and
// threadsafe!!
//
//===----------------------------------------------------------------------===//

#include "ReaderInternals.h"
#include "llvm/Module.h"
#include "llvm/Constants.h"
#include "llvm/GlobalVariable.h"
#include <algorithm>
#include <iostream>

using std::make_pair;

const Type *BytecodeParser::parseTypeConstant(const uchar *&Buf,
					      const uchar *EndBuf) {
  unsigned PrimType;
  if (read_vbr(Buf, EndBuf, PrimType)) return failure<const Type*>(0);

  const Type *Val = 0;
  if ((Val = Type::getPrimitiveType((Type::PrimitiveID)PrimType)))
    return Val;

  switch (PrimType) {
  case Type::FunctionTyID: {
    unsigned Typ;
    if (read_vbr(Buf, EndBuf, Typ)) return failure(Val);
    const Type *RetType = getType(Typ);
    if (RetType == 0) return failure(Val);

    unsigned NumParams;
    if (read_vbr(Buf, EndBuf, NumParams)) return failure(Val);

    std::vector<const Type*> Params;
    while (NumParams--) {
      if (read_vbr(Buf, EndBuf, Typ)) return failure(Val);
      const Type *Ty = getType(Typ);
      if (Ty == 0) return failure(Val);
      Params.push_back(Ty);
    }

    bool isVarArg = Params.size() && Params.back() == Type::VoidTy;
    if (isVarArg) Params.pop_back();

    return FunctionType::get(RetType, Params, isVarArg);
  }
  case Type::ArrayTyID: {
    unsigned ElTyp;
    if (read_vbr(Buf, EndBuf, ElTyp)) return failure(Val);
    const Type *ElementType = getType(ElTyp);
    if (ElementType == 0) return failure(Val);

    unsigned NumElements;
    if (read_vbr(Buf, EndBuf, NumElements)) return failure(Val);

    BCR_TRACE(5, "Array Type Constant #" << ElTyp << " size="
              << NumElements << "\n");
    return ArrayType::get(ElementType, NumElements);
  }
  case Type::StructTyID: {
    unsigned Typ;
    std::vector<const Type*> Elements;

    if (read_vbr(Buf, EndBuf, Typ)) return failure(Val);
    while (Typ) {         // List is terminated by void/0 typeid
      const Type *Ty = getType(Typ);
      if (Ty == 0) return failure(Val);
      Elements.push_back(Ty);

      if (read_vbr(Buf, EndBuf, Typ)) return failure(Val);
    }

    return StructType::get(Elements);
  }
  case Type::PointerTyID: {
    unsigned ElTyp;
    if (read_vbr(Buf, EndBuf, ElTyp)) return failure(Val);
    BCR_TRACE(5, "Pointer Type Constant #" << (ElTyp-14) << "\n");
    const Type *ElementType = getType(ElTyp);
    if (ElementType == 0) return failure(Val);
    return PointerType::get(ElementType);
  }

  case Type::OpaqueTyID: {
    return OpaqueType::get();
  }

  default:
    std::cerr << __FILE__ << ":" << __LINE__
              << ": Don't know how to deserialize"
              << " primitive Type " << PrimType << "\n";
    return failure(Val);
  }
}

// refineAbstractType - The callback method is invoked when one of the
// elements of TypeValues becomes more concrete...
//
void BytecodeParser::refineAbstractType(const DerivedType *OldType,
					const Type *NewType) {
  if (OldType == NewType &&
      OldType->isAbstract()) return;  // Type is modified, but same

  TypeValuesListTy::iterator I = find(MethodTypeValues.begin(),
				      MethodTypeValues.end(), OldType);
  if (I == MethodTypeValues.end()) {
    I = find(ModuleTypeValues.begin(), ModuleTypeValues.end(), OldType);
    assert(I != ModuleTypeValues.end() &&
	   "Can't refine a type I don't know about!");
  }

  if (OldType == NewType) {
    assert(!OldType->isAbstract());
    I->removeUserFromConcrete();
  } else {
    *I = NewType;  // Update to point to new, more refined type.
  }
}

// parseTypeConstants - We have to use this wierd code to handle recursive
// types.  We know that recursive types will only reference the current slab of
// values in the type plane, but they can forward reference types before they
// have been read.  For example, Type #0 might be '{ Ty#1 }' and Type #1 might
// be 'Ty#0*'.  When reading Type #0, type number one doesn't exist.  To fix
// this ugly problem, we pesimistically insert an opaque type for each type we
// are about to read.  This means that forward references will resolve to
// something and when we reread the type later, we can replace the opaque type
// with a new resolved concrete type.
//
void debug_type_tables();
bool BytecodeParser::parseTypeConstants(const uchar *&Buf, const uchar *EndBuf,
					TypeValuesListTy &Tab,
					unsigned NumEntries) {
  assert(Tab.size() == 0 && "should not have read type constants in before!");

  // Insert a bunch of opaque types to be resolved later...
  for (unsigned i = 0; i < NumEntries; ++i)
    Tab.push_back(PATypeHandle<Type>(OpaqueType::get(), this));

  // Loop through reading all of the types.  Forward types will make use of the
  // opaque types just inserted.
  //
  for (unsigned i = 0; i < NumEntries; ++i) {
    const Type *NewTy = parseTypeConstant(Buf, EndBuf), *OldTy = Tab[i].get();
    if (NewTy == 0) return failure(true);
    BCR_TRACE(4, "#" << i << ": Read Type Constant: '" << NewTy <<
              "' Replacing: " << OldTy << "\n");

    // Don't insertValue the new type... instead we want to replace the opaque
    // type with the new concrete value...
    //

    // Refine the abstract type to the new type.  This causes all uses of the
    // abstract type to use the newty.  This also will cause the opaque type
    // to be deleted...
    //
    ((DerivedType*)Tab[i].get())->refineAbstractTypeTo(NewTy);

    // This should have replace the old opaque type with the new type in the
    // value table... or with a preexisting type that was already in the system
    assert(Tab[i] != OldTy && "refineAbstractType didn't work!");
  }

  BCR_TRACE(5, "Resulting types:\n");
  for (unsigned i = 0; i < NumEntries; ++i) {
    BCR_TRACE(5, (void*)Tab[i].get() << " - " << Tab[i].get() << "\n");
  }
  debug_type_tables();
  return false;
}

bool BytecodeParser::parseConstantValue(const uchar *&Buf, const uchar *EndBuf,
                                        const Type *Ty, Constant *&V) {
  switch (Ty->getPrimitiveID()) {
  case Type::BoolTyID: {
    unsigned Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    if (Val != 0 && Val != 1) return failure(true);
    V = ConstantBool::get(Val == 1);
    break;
  }

  case Type::UByteTyID:   // Unsigned integer types...
  case Type::UShortTyID:
  case Type::UIntTyID: {
    unsigned Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    if (!ConstantUInt::isValueValidForType(Ty, Val)) return failure(true);
    V = ConstantUInt::get(Ty, Val);
    break;
  }

  case Type::ULongTyID: {
    uint64_t Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    V = ConstantUInt::get(Ty, Val);
    break;
  }

  case Type::SByteTyID:   // Unsigned integer types...
  case Type::ShortTyID:
  case Type::IntTyID: {
    int Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    if (!ConstantSInt::isValueValidForType(Ty, Val)) return failure(true);
    V = ConstantSInt::get(Ty, Val);
    break;
  }

  case Type::LongTyID: {
    int64_t Val;
    if (read_vbr(Buf, EndBuf, Val)) return failure(true);
    V = ConstantSInt::get(Ty, Val);
    break;
  }

  case Type::FloatTyID: {
    float F;
    if (input_data(Buf, EndBuf, &F, &F+1)) return failure(true);
    V = ConstantFP::get(Ty, F);
    break;
  }

  case Type::DoubleTyID: {
    double Val;
    if (input_data(Buf, EndBuf, &Val, &Val+1)) return failure(true);
    V = ConstantFP::get(Ty, Val);
    break;
  }

  case Type::TypeTyID:
    assert(0 && "Type constants should be handled seperately!!!");
    abort();

  case Type::ArrayTyID: {
    const ArrayType *AT = cast<const ArrayType>(Ty);
    unsigned NumElements = AT->getNumElements();

    std::vector<Constant*> Elements;
    while (NumElements--) {   // Read all of the elements of the constant.
      unsigned Slot;
      if (read_vbr(Buf, EndBuf, Slot)) return failure(true);
      Value *V = getValue(AT->getElementType(), Slot, false);
      if (!V || !isa<Constant>(V)) return failure(true);
      Elements.push_back(cast<Constant>(V));
    }
    V = ConstantArray::get(AT, Elements);
    break;
  }

  case Type::StructTyID: {
    const StructType *ST = cast<StructType>(Ty);
    const StructType::ElementTypes &ET = ST->getElementTypes();

    std::vector<Constant *> Elements;
    for (unsigned i = 0; i < ET.size(); ++i) {
      unsigned Slot;
      if (read_vbr(Buf, EndBuf, Slot)) return failure(true);
      Value *V = getValue(ET[i], Slot, false);
      if (!V || !isa<Constant>(V))
	return failure(true);
      Elements.push_back(cast<Constant>(V));
    }

    V = ConstantStruct::get(ST, Elements);
    break;
  }

  case Type::PointerTyID: {
    const PointerType *PT = cast<const PointerType>(Ty);
    unsigned SubClass;
    if (read_vbr(Buf, EndBuf, SubClass)) return failure(true);
    switch (SubClass) {
    case 0:    // ConstantPointerNull value...
      V = ConstantPointerNull::get(PT);
      break;

    case 1: {  // ConstantPointerRef value...
      unsigned Slot;
      if (read_vbr(Buf, EndBuf, Slot)) return failure(true);
      BCR_TRACE(4, "CPPR: Type: '" << Ty << "'  slot: " << Slot << "\n");

      // Check to see if we have already read this global variable yet...
      Value *Val = getValue(PT, Slot, false);
      GlobalValue *GV;
      if (Val) {
	if (!(GV = dyn_cast<GlobalValue>(Val))) return failure(true);
	BCR_TRACE(5, "Value Found in ValueTable!\n");
      } else {         // Nope... see if we have previously forward ref'd it
	GlobalRefsType::iterator I = GlobalRefs.find(make_pair(PT, Slot));
	if (I != GlobalRefs.end()) {
	  BCR_TRACE(5, "Previous forward ref found!\n");
	  GV = I->second;
	} else {
	  BCR_TRACE(5, "Creating new forward ref variable!\n");

	  // Create a placeholder for the global variable reference...
	  GlobalVariable *GVar =
	    new GlobalVariable(PT->getElementType(), false, true);

	  // Keep track of the fact that we have a forward ref to recycle it
	  GlobalRefs.insert(make_pair(make_pair(PT, Slot), GVar));

	  // Must temporarily push this value into the module table...
	  TheModule->getGlobalList().push_back(GVar);
	  GV = GVar;
	}
      }

      V = ConstantPointerRef::get(GV);
      break;
    }
    default:
      BCR_TRACE(5, "UNKNOWN Pointer Constant Type!\n");
      return failure(true);
    }
    break;
  }

  default:
    std::cerr << __FILE__ << ":" << __LINE__
              << ": Don't know how to deserialize constant value of type '"
              << Ty->getName() << "'\n";
    return failure(true);
  }

  return false;
}

bool BytecodeParser::ParseConstantPool(const uchar *&Buf, const uchar *EndBuf,
				       ValueTable &Tab,
				       TypeValuesListTy &TypeTab) {
  while (Buf < EndBuf) {
    unsigned NumEntries, Typ;

    if (read_vbr(Buf, EndBuf, NumEntries) ||
        read_vbr(Buf, EndBuf, Typ)) return failure(true);
    const Type *Ty = getType(Typ);
    if (Ty == 0) return failure(true);
    BCR_TRACE(3, "Type: '" << Ty << "'  NumEntries: " << NumEntries << "\n");

    if (Typ == Type::TypeTyID) {
      if (parseTypeConstants(Buf, EndBuf, TypeTab, NumEntries)) return true;
    } else {
      for (unsigned i = 0; i < NumEntries; ++i) {
	Constant *I;
	if (parseConstantValue(Buf, EndBuf, Ty, I)) return failure(true);
	BCR_TRACE(4, "Read Constant: '" << I << "'\n");
	if (insertValue(I, Tab) == -1) return failure(true);
      }
    }
  }

  if (Buf > EndBuf) return failure(true);
  return false;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "mcrouter/lib/network/ThriftTransport.h"

#include <folly/fibers/FiberManager.h>
#include <folly/io/async/AsyncSSLSocket.h>
#include <folly/io/async/AsyncSocket.h>
#include <folly/io/async/EventBase.h>
#include <thrift/lib/cpp2/async/RequestChannel.h>

#include "mcrouter/lib/fbi/cpp/LogFailure.h"
#include "mcrouter/lib/network/AsyncTlsToPlaintextSocket.h"
#include "mcrouter/lib/network/ConnectionOptions.h"
#include "mcrouter/lib/network/McFizzClient.h"
#include "mcrouter/lib/network/SecurityOptions.h"
#include "mcrouter/lib/network/SocketUtil.h"
#include "mcrouter/lib/network/ThreadLocalSSLContextProvider.h"

using folly::AsyncSocket;

namespace facebook {
namespace memcache {

ThriftTransportBase::ThriftTransportBase(
    folly::EventBase& eventBase,
    ConnectionOptions options)
    : eventBase_(eventBase), connectionOptions_(std::move(options)) {}

void ThriftTransportBase::closeNow() {
  resetClient();
}

void ThriftTransportBase::setConnectionStatusCallbacks(
    ConnectionStatusCallbacks callbacks) {
  connectionCallbacks_ = std::move(callbacks);

  if (connectionState_ == ConnectionState::Up && connectionCallbacks_.onUp) {
    // Connection retries not currently supported in thrift transport so pass 0
    connectionCallbacks_.onUp(*channel_->getTransport(), 0);
  }
}

void ThriftTransportBase::setRequestStatusCallbacks(
    RequestStatusCallbacks callbacks) {
  requestCallbacks_ = std::move(callbacks);
}

void ThriftTransportBase::setAuthorizationCallbacks(
    AuthorizationCallbacks callbacks) {
  authorizationCallbacks_ = std::move(callbacks);
}

void ThriftTransportBase::setThrottle(size_t maxInflight, size_t maxPending) {
  maxInflight_ = maxInflight;
  maxPending_ = maxPending;
}

Transport::RequestQueueStats ThriftTransportBase::getRequestQueueStats() const {
  return RequestQueueStats{0, 0};
}

void ThriftTransportBase::updateTimeoutsIfShorter(
    std::chrono::milliseconds /* connectTimeout */,
    std::chrono::milliseconds /* writeTimeout */) {}

const folly::AsyncTransportWrapper* ThriftTransportBase::getTransport() const {
  return nullptr;
}

double ThriftTransportBase::getRetransmitsPerKb() {
  return 0.0;
}

folly::AsyncTransportWrapper::UniquePtr
ThriftTransportBase::getConnectingSocket() {
  return folly::fibers::runInMainContext(
      [this]() -> folly::AsyncTransportWrapper::UniquePtr {
        auto expectedSocket = createAsyncSocket(eventBase_, connectionOptions_);
        if (expectedSocket.hasError()) {
          LOG_FAILURE(
              "ThriftTransport",
              failure::Category::kBadEnvironment,
              "{}",
              expectedSocket.error().what());
          return {};
        }
        auto socket = std::move(expectedSocket).value();

        auto sockAddressExpected = getSocketAddress(connectionOptions_);
        if (sockAddressExpected.hasError()) {
          const auto& ex = sockAddressExpected.error();
          LOG_FAILURE(
              "ThriftTransport",
              failure::Category::kBadEnvironment,
              "{}",
              ex.what());
          return {};
        }
        folly::SocketAddress address = std::move(sockAddressExpected).value();
        auto socketOptions = createSocketOptions(address, connectionOptions_);
        connectionState_ = ConnectionState::Connecting;

        const auto securityMech =
            connectionOptions_.accessPoint->getSecurityMech();
        if (securityMech == SecurityMech::TLS_TO_PLAINTEXT) {
          socket->setSendTimeout(connectionOptions_.writeTimeout.count());
          socket->getUnderlyingTransport<AsyncTlsToPlaintextSocket>()->connect(
              this,
              address,
              connectionOptions_.connectTimeout,
              std::move(socketOptions));
        } else if (securityMech == SecurityMech::TLS) {
          socket->setSendTimeout(connectionOptions_.writeTimeout.count());
          socket->getUnderlyingTransport<folly::AsyncSSLSocket>()->connect(
              this,
              address,
              connectionOptions_.connectTimeout.count(),
              socketOptions);
        } else if (securityMech == SecurityMech::TLS13_FIZZ) {
          auto fizzClient = socket->getUnderlyingTransport<McFizzClient>();
          fizzClient->setSendTimeout(connectionOptions_.writeTimeout.count());
          fizzClient->connect(
              this,
              address,
              connectionOptions_.connectTimeout.count(),
              socketOptions);
        } else {
          DCHECK(securityMech == SecurityMech::NONE);
          socket->setSendTimeout(connectionOptions_.writeTimeout.count());
          socket->getUnderlyingTransport<folly::AsyncSocket>()->connect(
              this,
              address,
              connectionOptions_.connectTimeout.count(),
              socketOptions);
        }
        return socket;
      });
}

apache::thrift::RocketClientChannel::Ptr ThriftTransportBase::createChannel() {
  // HHVM supports Debian 8 (EOL 2020-06-30), which includes OpenSSL 1.0.1;
  // Rocket/RSocket require ALPN, which requiers 1.0.2.
  //
  // For these platforms, build MCRouter client without a functional
  // Thrift transport, but continue to permit use as an async Memcache client
  // library for Hack
#ifndef MCROUTER_NOOP_THRIFT_CLIENT
  auto socket = getConnectingSocket();
  if (!socket) {
    return nullptr;
  }
  auto channel =
      apache::thrift::RocketClientChannel::newChannel(std::move(socket));
  channel->setProtocolId(apache::thrift::protocol::T_COMPACT_PROTOCOL);
  channel->setCloseCallback(this);
  return channel;
#else
  return nullptr;
#endif
}

void ThriftTransportBase::connectSuccess() noexcept {
  auto transport = channel_->getTransport();
  assert(
      transport != nullptr && connectionState_ == ConnectionState::Connecting);
  connectionState_ = ConnectionState::Up;
  McSSLUtil::finalizeClientTransport(transport);
  if (isAsyncSSLSocketMech(connectionOptions_.accessPoint->getSecurityMech())) {
    if (authorizationCallbacks_.onAuthorize &&
        !authorizationCallbacks_.onAuthorize(
            *transport->getUnderlyingTransport<AsyncSocket>(),
            connectionOptions_)) {
      if (connectionOptions_.securityOpts.sslAuthorizationEnforce) {
        // Enforcement is enabled, close the connection.
        closeNow();
        return;
      }
    }
  }

  if (connectionCallbacks_.onUp) {
    // Connection retries not currently supported in thrift transport so pass 0
    connectionCallbacks_.onUp(*channel_->getTransport(), 0);
  }
  VLOG(5) << "[ThriftTransport] Connection successfully established!";
}

void ThriftTransportBase::connectErr(
    const folly::AsyncSocketException& ex) noexcept {
  assert(connectionState_ == ConnectionState::Connecting);

  connectionState_ = ConnectionState::Error;
  connectionTimedOut_ =
      (ex.getType() == folly::AsyncSocketException::TIMED_OUT);
  if (connectionCallbacks_.onDown) {
    ConnectionDownReason reason = ConnectionDownReason::CONNECT_ERROR;
    if (connectionTimedOut_) {
      reason = ConnectionDownReason::CONNECT_ERROR;
    }
    connectionCallbacks_.onDown(reason, 0);
  }
  VLOG(2) << "[ThriftTransport] Error connecting: " << ex.what();
}

void ThriftTransportBase::channelClosed() {
  VLOG(3) << "[ThriftTransport] Channel closed.";
  // If callbacks configured and connection up, defer reset
  // to the callback
  if (connectionCallbacks_.onDown && connectionState_ == ConnectionState::Up) {
    connectionState_ = ConnectionState::Down;
    connectionCallbacks_.onDown(ConnectionDownReason::ABORTED, 0);
  }
  resetClient();
}

#ifndef LIBMC_FBTRACE_DISABLE
void ThriftTransportUtil::traceRequest(
    const carbon::MessageCommon& request,
    apache::thrift::RpcOptions& rpcOptions) {
  if (UNLIKELY(!request.traceContext().empty())) {
    folly::fibers::runInMainContext(
        [&]() { traceRequestImpl(request, rpcOptions); });
  }
}

void ThriftTransportUtil::traceRequestImpl(
    const carbon::MessageCommon& request,
    apache::thrift::RpcOptions& rpcOptions) {
  auto artilleryTraceIDs =
      facebook::contextprop::SerDeHelper::getArtilleryTraceIDsFromLegacyHeader(
          request.traceContext());
  rpcOptions.setWriteHeader(
      facebook::contextprop::ContextpropConstants_constants::
          artillery_trace_ids_header_,
      facebook::contextprop::SerDeHelper::encodeAndSerialize<
          facebook::contextprop::ArtilleryTraceIDs>(artilleryTraceIDs));
}

void ThriftTransportUtil::traceResponseImpl(
    carbon::MessageCommon& response,
    const std::map<std::string, std::string>& responseHeaders) {
  auto artilleryTraceIDs = contextprop::SerDeHelper::decodeAndDeserialize<
      facebook::contextprop::ArtilleryTraceIDs>(
      responseHeaders,
      facebook::contextprop::ContextpropConstants_constants::
          artillery_trace_ids_header_);
  if (artilleryTraceIDs) {
    response.setTraceContext(
        facebook::contextprop::SerDeHelper::convertToLegacyTraceContext(
            *artilleryTraceIDs));
  }
}
#endif

apache::thrift::RpcOptions ThriftTransportUtil::getRpcOptions(
    std::chrono::milliseconds timeout) {
  apache::thrift::RpcOptions rpcOptions;
  rpcOptions.setTimeout(timeout);
  rpcOptions.setClientOnlyTimeouts(true);
  return rpcOptions;
}

} // namespace memcache
} // namespace facebook
<commit_msg>Support compression in ThriftTransport<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "mcrouter/lib/network/ThriftTransport.h"

#include <folly/fibers/FiberManager.h>
#include <folly/io/async/AsyncSSLSocket.h>
#include <folly/io/async/AsyncSocket.h>
#include <folly/io/async/EventBase.h>
#include <thrift/lib/cpp2/async/RequestChannel.h>

#include "mcrouter/lib/fbi/cpp/LogFailure.h"
#include "mcrouter/lib/network/AsyncTlsToPlaintextSocket.h"
#include "mcrouter/lib/network/ConnectionOptions.h"
#include "mcrouter/lib/network/McFizzClient.h"
#include "mcrouter/lib/network/SecurityOptions.h"
#include "mcrouter/lib/network/SocketUtil.h"
#include "mcrouter/lib/network/ThreadLocalSSLContextProvider.h"

using folly::AsyncSocket;

namespace facebook {
namespace memcache {

ThriftTransportBase::ThriftTransportBase(
    folly::EventBase& eventBase,
    ConnectionOptions options)
    : eventBase_(eventBase), connectionOptions_(std::move(options)) {}

void ThriftTransportBase::closeNow() {
  resetClient();
}

void ThriftTransportBase::setConnectionStatusCallbacks(
    ConnectionStatusCallbacks callbacks) {
  connectionCallbacks_ = std::move(callbacks);

  if (connectionState_ == ConnectionState::Up && connectionCallbacks_.onUp) {
    // Connection retries not currently supported in thrift transport so pass 0
    connectionCallbacks_.onUp(*channel_->getTransport(), 0);
  }
}

void ThriftTransportBase::setRequestStatusCallbacks(
    RequestStatusCallbacks callbacks) {
  requestCallbacks_ = std::move(callbacks);
}

void ThriftTransportBase::setAuthorizationCallbacks(
    AuthorizationCallbacks callbacks) {
  authorizationCallbacks_ = std::move(callbacks);
}

void ThriftTransportBase::setThrottle(size_t maxInflight, size_t maxPending) {
  maxInflight_ = maxInflight;
  maxPending_ = maxPending;
}

Transport::RequestQueueStats ThriftTransportBase::getRequestQueueStats() const {
  return RequestQueueStats{0, 0};
}

void ThriftTransportBase::updateTimeoutsIfShorter(
    std::chrono::milliseconds /* connectTimeout */,
    std::chrono::milliseconds /* writeTimeout */) {}

const folly::AsyncTransportWrapper* ThriftTransportBase::getTransport() const {
  return nullptr;
}

double ThriftTransportBase::getRetransmitsPerKb() {
  return 0.0;
}

folly::AsyncTransportWrapper::UniquePtr
ThriftTransportBase::getConnectingSocket() {
  return folly::fibers::runInMainContext(
      [this]() -> folly::AsyncTransportWrapper::UniquePtr {
        auto expectedSocket = createAsyncSocket(eventBase_, connectionOptions_);
        if (expectedSocket.hasError()) {
          LOG_FAILURE(
              "ThriftTransport",
              failure::Category::kBadEnvironment,
              "{}",
              expectedSocket.error().what());
          return {};
        }
        auto socket = std::move(expectedSocket).value();

        auto sockAddressExpected = getSocketAddress(connectionOptions_);
        if (sockAddressExpected.hasError()) {
          const auto& ex = sockAddressExpected.error();
          LOG_FAILURE(
              "ThriftTransport",
              failure::Category::kBadEnvironment,
              "{}",
              ex.what());
          return {};
        }
        folly::SocketAddress address = std::move(sockAddressExpected).value();
        auto socketOptions = createSocketOptions(address, connectionOptions_);
        connectionState_ = ConnectionState::Connecting;

        const auto securityMech =
            connectionOptions_.accessPoint->getSecurityMech();
        if (securityMech == SecurityMech::TLS_TO_PLAINTEXT) {
          socket->setSendTimeout(connectionOptions_.writeTimeout.count());
          socket->getUnderlyingTransport<AsyncTlsToPlaintextSocket>()->connect(
              this,
              address,
              connectionOptions_.connectTimeout,
              std::move(socketOptions));
        } else if (securityMech == SecurityMech::TLS) {
          socket->setSendTimeout(connectionOptions_.writeTimeout.count());
          socket->getUnderlyingTransport<folly::AsyncSSLSocket>()->connect(
              this,
              address,
              connectionOptions_.connectTimeout.count(),
              socketOptions);
        } else if (securityMech == SecurityMech::TLS13_FIZZ) {
          auto fizzClient = socket->getUnderlyingTransport<McFizzClient>();
          fizzClient->setSendTimeout(connectionOptions_.writeTimeout.count());
          fizzClient->connect(
              this,
              address,
              connectionOptions_.connectTimeout.count(),
              socketOptions);
        } else {
          DCHECK(securityMech == SecurityMech::NONE);
          socket->setSendTimeout(connectionOptions_.writeTimeout.count());
          socket->getUnderlyingTransport<folly::AsyncSocket>()->connect(
              this,
              address,
              connectionOptions_.connectTimeout.count(),
              socketOptions);
        }
        return socket;
      });
}

apache::thrift::RocketClientChannel::Ptr ThriftTransportBase::createChannel() {
  // HHVM supports Debian 8 (EOL 2020-06-30), which includes OpenSSL 1.0.1;
  // Rocket/RSocket require ALPN, which requiers 1.0.2.
  //
  // For these platforms, build MCRouter client without a functional
  // Thrift transport, but continue to permit use as an async Memcache client
  // library for Hack
#ifndef MCROUTER_NOOP_THRIFT_CLIENT
  auto socket = getConnectingSocket();
  if (!socket) {
    return nullptr;
  }
  auto channel =
      apache::thrift::RocketClientChannel::newChannel(std::move(socket));
  channel->setProtocolId(apache::thrift::protocol::T_COMPACT_PROTOCOL);
  channel->setCloseCallback(this);
  if (connectionOptions_.thriftCompression) {
    apache::thrift::CodecConfig codec;
    codec.zstdConfig_ref() = apache::thrift::ZstdCompressionCodecConfig();
    apache::thrift::CompressionConfig compressionConfig;
    compressionConfig.codecConfig_ref() = std::move(codec);
    channel->setDefaultCompressionConfig(std::move(compressionConfig));
  }

  return channel;
#else
  return nullptr;
#endif
}

void ThriftTransportBase::connectSuccess() noexcept {
  auto transport = channel_->getTransport();
  assert(
      transport != nullptr && connectionState_ == ConnectionState::Connecting);
  connectionState_ = ConnectionState::Up;
  McSSLUtil::finalizeClientTransport(transport);
  if (isAsyncSSLSocketMech(connectionOptions_.accessPoint->getSecurityMech())) {
    if (authorizationCallbacks_.onAuthorize &&
        !authorizationCallbacks_.onAuthorize(
            *transport->getUnderlyingTransport<AsyncSocket>(),
            connectionOptions_)) {
      if (connectionOptions_.securityOpts.sslAuthorizationEnforce) {
        // Enforcement is enabled, close the connection.
        closeNow();
        return;
      }
    }
  }

  if (connectionCallbacks_.onUp) {
    // Connection retries not currently supported in thrift transport so pass 0
    connectionCallbacks_.onUp(*channel_->getTransport(), 0);
  }
  VLOG(5) << "[ThriftTransport] Connection successfully established!";
}

void ThriftTransportBase::connectErr(
    const folly::AsyncSocketException& ex) noexcept {
  assert(connectionState_ == ConnectionState::Connecting);

  connectionState_ = ConnectionState::Error;
  connectionTimedOut_ =
      (ex.getType() == folly::AsyncSocketException::TIMED_OUT);
  if (connectionCallbacks_.onDown) {
    ConnectionDownReason reason = ConnectionDownReason::CONNECT_ERROR;
    if (connectionTimedOut_) {
      reason = ConnectionDownReason::CONNECT_ERROR;
    }
    connectionCallbacks_.onDown(reason, 0);
  }
  VLOG(2) << "[ThriftTransport] Error connecting: " << ex.what();
}

void ThriftTransportBase::channelClosed() {
  VLOG(3) << "[ThriftTransport] Channel closed.";
  // If callbacks configured and connection up, defer reset
  // to the callback
  if (connectionCallbacks_.onDown && connectionState_ == ConnectionState::Up) {
    connectionState_ = ConnectionState::Down;
    connectionCallbacks_.onDown(ConnectionDownReason::ABORTED, 0);
  }
  resetClient();
}

#ifndef LIBMC_FBTRACE_DISABLE
void ThriftTransportUtil::traceRequest(
    const carbon::MessageCommon& request,
    apache::thrift::RpcOptions& rpcOptions) {
  if (UNLIKELY(!request.traceContext().empty())) {
    folly::fibers::runInMainContext(
        [&]() { traceRequestImpl(request, rpcOptions); });
  }
}

void ThriftTransportUtil::traceRequestImpl(
    const carbon::MessageCommon& request,
    apache::thrift::RpcOptions& rpcOptions) {
  auto artilleryTraceIDs =
      facebook::contextprop::SerDeHelper::getArtilleryTraceIDsFromLegacyHeader(
          request.traceContext());
  rpcOptions.setWriteHeader(
      facebook::contextprop::ContextpropConstants_constants::
          artillery_trace_ids_header_,
      facebook::contextprop::SerDeHelper::encodeAndSerialize<
          facebook::contextprop::ArtilleryTraceIDs>(artilleryTraceIDs));
}

void ThriftTransportUtil::traceResponseImpl(
    carbon::MessageCommon& response,
    const std::map<std::string, std::string>& responseHeaders) {
  auto artilleryTraceIDs = contextprop::SerDeHelper::decodeAndDeserialize<
      facebook::contextprop::ArtilleryTraceIDs>(
      responseHeaders,
      facebook::contextprop::ContextpropConstants_constants::
          artillery_trace_ids_header_);
  if (artilleryTraceIDs) {
    response.setTraceContext(
        facebook::contextprop::SerDeHelper::convertToLegacyTraceContext(
            *artilleryTraceIDs));
  }
}
#endif

apache::thrift::RpcOptions ThriftTransportUtil::getRpcOptions(
    std::chrono::milliseconds timeout) {
  apache::thrift::RpcOptions rpcOptions;
  rpcOptions.setTimeout(timeout);
  rpcOptions.setClientOnlyTimeouts(true);
  return rpcOptions;
}

} // namespace memcache
} // namespace facebook
<|endoftext|>


<commit_before>#include "../serialize_props.h"

#include "../cpp_utils/std_make_unique.h"

#include <QCheckBox>
#include <QComboBox>
#include <QDoubleSpinBox>
#include <QSpinBox>
#include <QLineEdit>
#include <QPlainTextEdit>

#include <cassert>
#include <istream>
#include <ostream>

namespace qu {

template <typename Object, typename Reader, typename Writer>
static std::unique_ptr<PropertySerializer> createPropertySerializer(
        Object * obj, Reader r, Writer w )
{
    struct S final : PropertySerializer
    {
        S( Object * obj, Reader && r, Writer && w )
            : obj(obj), r(std::move(r)), w(std::move(w)) {}

        virtual QObject * getObject() const override
        {
            return obj;
        }

        virtual void read ( std::istream & stream ) override
        {
            r( stream, obj );
        }

        virtual void write( std::ostream & stream ) override
        {
            w( stream, obj );
        }

        virtual std::unique_ptr<PropertySerializer> clone() const override
        {
            return std::make_unique<S>(*this);
        }

        Object * obj;
        Reader r;
        Writer w;
    };

    return std::make_unique<S>( obj, std::move(r), std::move(w) );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QCheckBox * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QCheckBox * obj )
    {
        bool b;
        stream >> b;
        obj->setChecked( b );
    },
        []( std::ostream & stream, const QCheckBox * obj )
    {
        stream << obj->isChecked();
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QSpinBox * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QSpinBox * obj )
    {
        int i;
        stream >> i;
        obj->setValue( i );
    },
        []( std::ostream & stream, const QSpinBox * obj )
    {
        stream << obj->value();
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QDoubleSpinBox * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QDoubleSpinBox * obj )
    {
        double d;
        stream >> d;
        obj->setValue( d );
    },
        []( std::ostream & stream, const QDoubleSpinBox * obj )
    {
        stream << obj->value();
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QComboBox * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QComboBox * obj )
    {
        int index;
        stream >> index;
        obj->setCurrentIndex( index );
    },
        []( std::ostream & stream, const QComboBox * obj )
    {
        stream << obj->currentIndex();
    } );
}

static std::string unescapeAllWhiteSpaces( const std::string & s )
{
    auto result = std::string();
    if ( s == "\\0" )
        return result;
    auto it = begin(s);
    while ( it != s.end() )
    {
        auto c = *it;
        ++it;
        if ( c!='\\' )
        {
            result.push_back(c);
            continue;
        }
        c = *it;
        ++it;
        switch ( c )
        {
        case 't' : result.push_back( '\t' ); break;
        case 'n' : result.push_back( '\n' ); break;
        case 'v' : result.push_back( '\v' ); break;
        case 'f' : result.push_back( '\f' ); break;
        case 'r' : result.push_back( '\r' ); break;
        case '\\': result.push_back( '\\' ); break;
        case 's' : result.push_back( ' '  ); break;
        default:
            assert(!"Unknown whitespace character in string.");
            result.push_back(c);
            break;
        }
    }
    return result;
}

static std::string escapeAllWhiteSpaces( const std::string & s )
{
    if ( s.empty() )
        return "\\0";
    auto result = std::string();
    for ( auto c : s )
    {
        if ( !isspace(c) && c!='\\' )
        {
            result.push_back(c);
            continue;
        }
        result.push_back('\\');
        switch ( c )
        {
        case '\t': result.push_back( 't' ); break;
        case '\n': result.push_back( 'n' ); break;
        case '\v': result.push_back( 'v' ); break;
        case '\f': result.push_back( 'f' ); break;
        case '\r': result.push_back( 'r' ); break;
        case '\\': result.push_back( '\\'); break;
        case ' ' : result.push_back( 's' ); break;
        default:
            assert(!"Unknown whitespace character in string.");
            result.push_back(c);
            break;
        }
    }
    return result;
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QLineEdit * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QLineEdit * obj )
    {
        std::string s;
        stream >> s;
        obj->setText( QString::fromStdString(
            unescapeAllWhiteSpaces(s)) );
    },
        []( std::ostream & stream, const QLineEdit * obj )
    {
        stream << escapeAllWhiteSpaces(
            obj->text().toStdString() );
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QPlainTextEdit *obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QPlainTextEdit * obj )
    {
        std::string s;
        stream >> s;
        obj->setPlainText( QString::fromStdString(
            unescapeAllWhiteSpaces(s)) );
    },
        []( std::ostream & stream, const QPlainTextEdit * obj )
    {
        stream << escapeAllWhiteSpaces(
            obj->toPlainText().toStdString() );
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QTabWidget *obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QTabWidget * obj )
    {
        int index;
        stream >> index;
        if ( index < obj->count() )
            obj->setCurrentIndex( index );
    },
        []( std::ostream & stream, const QTabWidget * obj )
    {
        stream << obj->currentIndex();
    } );
}

} // namespace qu
<commit_msg>Bugfix: Fixed compile-time error due to wrong include path.<commit_after>#include "serialize_props.h"

#include "../cpp_utils/std_make_unique.h"

#include <QCheckBox>
#include <QComboBox>
#include <QDoubleSpinBox>
#include <QSpinBox>
#include <QLineEdit>
#include <QPlainTextEdit>

#include <cassert>
#include <istream>
#include <ostream>

namespace qu {

template <typename Object, typename Reader, typename Writer>
static std::unique_ptr<PropertySerializer> createPropertySerializer(
        Object * obj, Reader r, Writer w )
{
    struct S final : PropertySerializer
    {
        S( Object * obj, Reader && r, Writer && w )
            : obj(obj), r(std::move(r)), w(std::move(w)) {}

        virtual QObject * getObject() const override
        {
            return obj;
        }

        virtual void read ( std::istream & stream ) override
        {
            r( stream, obj );
        }

        virtual void write( std::ostream & stream ) override
        {
            w( stream, obj );
        }

        virtual std::unique_ptr<PropertySerializer> clone() const override
        {
            return std::make_unique<S>(*this);
        }

        Object * obj;
        Reader r;
        Writer w;
    };

    return std::make_unique<S>( obj, std::move(r), std::move(w) );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QCheckBox * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QCheckBox * obj )
    {
        bool b;
        stream >> b;
        obj->setChecked( b );
    },
        []( std::ostream & stream, const QCheckBox * obj )
    {
        stream << obj->isChecked();
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QSpinBox * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QSpinBox * obj )
    {
        int i;
        stream >> i;
        obj->setValue( i );
    },
        []( std::ostream & stream, const QSpinBox * obj )
    {
        stream << obj->value();
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QDoubleSpinBox * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QDoubleSpinBox * obj )
    {
        double d;
        stream >> d;
        obj->setValue( d );
    },
        []( std::ostream & stream, const QDoubleSpinBox * obj )
    {
        stream << obj->value();
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QComboBox * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QComboBox * obj )
    {
        int index;
        stream >> index;
        obj->setCurrentIndex( index );
    },
        []( std::ostream & stream, const QComboBox * obj )
    {
        stream << obj->currentIndex();
    } );
}

static std::string unescapeAllWhiteSpaces( const std::string & s )
{
    auto result = std::string();
    if ( s == "\\0" )
        return result;
    auto it = begin(s);
    while ( it != s.end() )
    {
        auto c = *it;
        ++it;
        if ( c!='\\' )
        {
            result.push_back(c);
            continue;
        }
        c = *it;
        ++it;
        switch ( c )
        {
        case 't' : result.push_back( '\t' ); break;
        case 'n' : result.push_back( '\n' ); break;
        case 'v' : result.push_back( '\v' ); break;
        case 'f' : result.push_back( '\f' ); break;
        case 'r' : result.push_back( '\r' ); break;
        case '\\': result.push_back( '\\' ); break;
        case 's' : result.push_back( ' '  ); break;
        default:
            assert(!"Unknown whitespace character in string.");
            result.push_back(c);
            break;
        }
    }
    return result;
}

static std::string escapeAllWhiteSpaces( const std::string & s )
{
    if ( s.empty() )
        return "\\0";
    auto result = std::string();
    for ( auto c : s )
    {
        if ( !isspace(c) && c!='\\' )
        {
            result.push_back(c);
            continue;
        }
        result.push_back('\\');
        switch ( c )
        {
        case '\t': result.push_back( 't' ); break;
        case '\n': result.push_back( 'n' ); break;
        case '\v': result.push_back( 'v' ); break;
        case '\f': result.push_back( 'f' ); break;
        case '\r': result.push_back( 'r' ); break;
        case '\\': result.push_back( '\\'); break;
        case ' ' : result.push_back( 's' ); break;
        default:
            assert(!"Unknown whitespace character in string.");
            result.push_back(c);
            break;
        }
    }
    return result;
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QLineEdit * obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QLineEdit * obj )
    {
        std::string s;
        stream >> s;
        obj->setText( QString::fromStdString(
            unescapeAllWhiteSpaces(s)) );
    },
        []( std::ostream & stream, const QLineEdit * obj )
    {
        stream << escapeAllWhiteSpaces(
            obj->text().toStdString() );
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QPlainTextEdit *obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QPlainTextEdit * obj )
    {
        std::string s;
        stream >> s;
        obj->setPlainText( QString::fromStdString(
            unescapeAllWhiteSpaces(s)) );
    },
        []( std::ostream & stream, const QPlainTextEdit * obj )
    {
        stream << escapeAllWhiteSpaces(
            obj->toPlainText().toStdString() );
    } );
}

std::unique_ptr<PropertySerializer> createPropertySerializer( QTabWidget *obj )
{
    return createPropertySerializer( obj,
        []( std::istream & stream, QTabWidget * obj )
    {
        int index;
        stream >> index;
        if ( index < obj->count() )
            obj->setCurrentIndex( index );
    },
        []( std::ostream & stream, const QTabWidget * obj )
    {
        stream << obj->currentIndex();
    } );
}

} // namespace qu
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS pchfix02 (1.14.28); FILE MERGED 2006/09/01 17:37:08 kaib 1.14.28.1: #i68856# Added header markers and pch files<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM 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) version 2.1 dated February 1999.

#ifndef MFEM_DOFTRANSFORM
#define MFEM_DOFTRANSFORM

#include "../config/config.hpp"
#include "../linalg/linalg.hpp"
#include "intrules.hpp"
#include "fe.hpp"

namespace mfem
{

class DofTransformation
{
protected:
   int height_;
   int width_;

   Array<int> Fo;

   DofTransformation(int height, int width)
      : height_(height), width_(width) {}

public:

   inline int Height() const { return height_; }
   inline int NumRows() const { return height_; }
   inline int Width() const { return width_; }
   inline int NumCols() const { return width_; }

   inline void SetFaceOrientations(const Array<int> & face_orientation)
   { Fo = face_orientation; }

   virtual void TransformPrimal(const double *, double *) const = 0;

   virtual void TransformPrimal(const Vector &, Vector &) const;

   virtual void TransformPrimalRows(const DenseMatrix &, DenseMatrix &) const;

   virtual void TransformPrimalCols(const DenseMatrix &, DenseMatrix &) const;

   virtual void InvTransformPrimal(const double *, double *) const = 0;

   virtual void InvTransformPrimal(const Vector &, Vector &) const;

   virtual void TransformDual(const double *, double *) const = 0;
   virtual void TransformDual(const Vector &, Vector &) const;

   virtual void TransformDual(const DenseMatrix &, DenseMatrix &) const;

   virtual void TransformDualRows(const DenseMatrix &, DenseMatrix &) const;

   virtual void TransformDualCols(const DenseMatrix &, DenseMatrix &) const;

   virtual ~DofTransformation() {}
};

void TransformPrimal(const DofTransformation *, const DofTransformation *,
                     const DenseMatrix &, DenseMatrix &);

void TransformDual(const DofTransformation *, const DofTransformation *,
                   const DenseMatrix &, DenseMatrix &);

class VDofTransformation : public DofTransformation
{
private:
   int vdim_;
   int ordering_;
   DofTransformation * doftrans_;

public:
   VDofTransformation(int vdim = 1, int ordering = 0)
      : DofTransformation(0,0),
        vdim_(vdim), ordering_(ordering),
        doftrans_(NULL) {}

   VDofTransformation(DofTransformation & doftrans, int vdim = 1,
                      int ordering = 0)
      : DofTransformation(vdim * doftrans.Height(), vdim * doftrans.Width()),
        vdim_(vdim), ordering_(ordering),
        doftrans_(&doftrans) {}

   inline void SetVDim(int vdim)
   {
      vdim_ = vdim;
      if (doftrans_)
      {
         height_ = vdim_ * doftrans_->Height();
         width_  = vdim_ * doftrans_->Width();
      }
   }

   inline void SetDofTransformation(DofTransformation & doftrans)
   {
      height_ = vdim_ * doftrans.Height();
      width_  = vdim_ * doftrans.Width();
      doftrans_ = &doftrans;
   }

   inline void SetFaceOrientation(const Array<int> & face_orientation)
   { Fo = face_orientation; doftrans_->SetFaceOrientations(face_orientation);}

   using DofTransformation::TransformPrimal;
   using DofTransformation::InvTransformPrimal;
   using DofTransformation::TransformDual;

   void TransformPrimal(const double *, double *) const;
   void InvTransformPrimal(const double *, double *) const;
   void TransformDual(const double *, double *) const;
};

class ND_DofTransformation : public DofTransformation
{
protected:
   static const double T_data[24];
   static const double TInv_data[24];
   static const DenseTensor T, TInv;
   int order;

   ND_DofTransformation(int height, int width, int order);

public:
   static const DenseMatrix & GetFaceTransform(int ori) { return T(ori); }
   static const DenseMatrix & GetFaceInverseTransform(int ori)
   { return TInv(ori); }
};

class ND_TetDofTransformation : public ND_DofTransformation
{
public:
   ND_TetDofTransformation(int order);

   using DofTransformation::TransformPrimal;
   using DofTransformation::InvTransformPrimal;
   using DofTransformation::TransformDual;

   void TransformPrimal(const double *, double *) const;

   void InvTransformPrimal(const double *, double *) const;

   void TransformDual(const double *, double *) const;
};

class ND_WedgeDofTransformation : public ND_DofTransformation
{
public:
   ND_WedgeDofTransformation(int order);

   using DofTransformation::TransformPrimal;
   using DofTransformation::InvTransformPrimal;
   using DofTransformation::TransformDual;

   void TransformPrimal(const double *, double *) const;

   void InvTransformPrimal(const double *, double *) const;

   void TransformDual(const double *, double *) const;
};

} // namespace mfem

#endif // MFEM_DOFTRANSFORM
<commit_msg>Adding documentation to the classes declared in the doftrans file<commit_after>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM 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) version 2.1 dated February 1999.

#ifndef MFEM_DOFTRANSFORM
#define MFEM_DOFTRANSFORM

#include "../config/config.hpp"
#include "../linalg/linalg.hpp"
#include "intrules.hpp"
#include "fe.hpp"

namespace mfem
{

/** The DofTransformation class is an abstract base class for a family of
    transformations that map local degrees of freedom (DoFs), contained within
    individual elements, to global degrees of freedom, stored within
    GridFunction objects. These transformations are necessary to ensure that
    basis functions in neighboring elements align corretly. Closely related but
    complimentary transformations are required for the entries stored in
    LinearForm and BilinearForm objects.  The DofTransformation class is
    designed to apply the action of both of these types of DoF transformations.
*/
class DofTransformation
{
protected:
   int height_;
   int width_;

   Array<int> Fo;

   DofTransformation(int height, int width)
      : height_(height), width_(width) {}

public:

   inline int Height() const { return height_; }
   inline int NumRows() const { return height_; }
   inline int Width() const { return width_; }
   inline int NumCols() const { return width_; }

   /** @brief Configure the transformation using face orientations for the
       current element. */
   /// The face_orientation array can be obtained from Mesh::GetElementFaces.
   inline void SetFaceOrientations(const Array<int> & face_orientation)
   { Fo = face_orientation; }

   /** Transform local DoFs to align with the global DoFs.  For example, this
       transformation can be used to map the local vector computed by
       FiniteElement::Project() to the transformed vector stored within a
       GridFunction object. */
   virtual void TransformPrimal(const double *, double *) const = 0;
   virtual void TransformPrimal(const Vector &, Vector &) const;

   /// Transform groups of DoFs stored as dense matrices
   virtual void TransformPrimalRows(const DenseMatrix &, DenseMatrix &) const;
   virtual void TransformPrimalCols(const DenseMatrix &, DenseMatrix &) const;

   /** Inverse transform local DoFs.  Used to transform DoFs from a global
       vector back to their element-local form.  For example, this must be used
       to transform the vector obtained using GridFunction::GetSubVector
       before it can be used to compute a local interpolation.
   */
   virtual void InvTransformPrimal(const double *, double *) const = 0;
   virtual void InvTransformPrimal(const Vector &, Vector &) const;

   /** Transform dual DoFs as computed by a LinearFormIntegrator before summing
       into a LinearForm object. */
   virtual void TransformDual(const double *, double *) const = 0;
   virtual void TransformDual(const Vector &, Vector &) const;

   /** Transform a matrix of dual DoFs entries as computed by a
       BilinearFormIntegrator before summing into a BilinearForm object. */
   virtual void TransformDual(const DenseMatrix &, DenseMatrix &) const;

   /// Transform groups of dual DoFs stored as dense matrices
   virtual void TransformDualRows(const DenseMatrix &, DenseMatrix &) const;
   virtual void TransformDualCols(const DenseMatrix &, DenseMatrix &) const;

   virtual ~DofTransformation() {}
};

/** Transform a matrix of DoFs entries from different finite element spaces
    as computed by a DiscreteInterpolator before copying into a
    DiscreteLinearOperator.
*/
void TransformPrimal(const DofTransformation *, const DofTransformation *,
                     const DenseMatrix &, DenseMatrix &);

/** Transform a matrix of dual DoFs entries from different finite element spaces
    as computed by a BilinearFormIntegrator before summing into a
    MixedBilinearForm object.
*/
void TransformDual(const DofTransformation *, const DofTransformation *,
                   const DenseMatrix &, DenseMatrix &);

/** The VDofTransformation class implements a nested transformation where an
    arbitrary DofTransformation is replicated with a vdim >= 1.
*/
class VDofTransformation : public DofTransformation
{
private:
   int vdim_;
   int ordering_;
   DofTransformation * doftrans_;

public:
   /** Default constructor which requires that SetDofTransformation be called
       before use. */
   VDofTransformation(int vdim = 1, int ordering = 0)
      : DofTransformation(0,0),
        vdim_(vdim), ordering_(ordering),
        doftrans_(NULL) {}

   /// Constructor with a known DofTransformation
   VDofTransformation(DofTransformation & doftrans, int vdim = 1,
                      int ordering = 0)
      : DofTransformation(vdim * doftrans.Height(), vdim * doftrans.Width()),
        vdim_(vdim), ordering_(ordering),
        doftrans_(&doftrans) {}

   // Set or change the vdim parameter
   inline void SetVDim(int vdim)
   {
      vdim_ = vdim;
      if (doftrans_)
      {
         height_ = vdim_ * doftrans_->Height();
         width_  = vdim_ * doftrans_->Width();
      }
   }

   // Set or change the nested DofTransformation object
   inline void SetDofTransformation(DofTransformation & doftrans)
   {
      height_ = vdim_ * doftrans.Height();
      width_  = vdim_ * doftrans.Width();
      doftrans_ = &doftrans;
   }

   inline void SetFaceOrientation(const Array<int> & face_orientation)
   { Fo = face_orientation; doftrans_->SetFaceOrientations(face_orientation);}

   using DofTransformation::TransformPrimal;
   using DofTransformation::InvTransformPrimal;
   using DofTransformation::TransformDual;

   void TransformPrimal(const double *, double *) const;
   void InvTransformPrimal(const double *, double *) const;
   void TransformDual(const double *, double *) const;
};

/** Abstract base class for high-order Nedelec spaces on elements with
    triangular faces.

    The Nedelec DoFs on the interior of triangular faces come in pairs
    which share an interpolation point but have different vector
    directions.  These directions depend on the orientation of the
    face and can therefore differ in neighboring elements.  The
    mapping required to transform these DoFs can be implemented as
    series of 2x2 linear transformations.  The raw data for these
    linear transformations is stored in the T_data and TInv_data
    arrays and can be accessed as DenseMatrices using the
    GetFaceTransform() and GetFaceInverseTransform() methods.
*/
class ND_DofTransformation : public DofTransformation
{
protected:
   static const double T_data[24];
   static const double TInv_data[24];
   static const DenseTensor T, TInv;
   int order;

   ND_DofTransformation(int height, int width, int order);

public:
   // Return the 2x2 transformation operator for the given face orientation
   static const DenseMatrix & GetFaceTransform(int ori) { return T(ori); }

   // Return the 2x2 inverse transformation operator
   static const DenseMatrix & GetFaceInverseTransform(int ori)
   { return TInv(ori); }
};

/// DoF transformation implementation for the Nedelec basis on tetrahedra
class ND_TetDofTransformation : public ND_DofTransformation
{
public:
   ND_TetDofTransformation(int order);

   using DofTransformation::TransformPrimal;
   using DofTransformation::InvTransformPrimal;
   using DofTransformation::TransformDual;

   void TransformPrimal(const double *, double *) const;

   void InvTransformPrimal(const double *, double *) const;

   void TransformDual(const double *, double *) const;
};

/// DoF transformation implementation for the Nedelec basis on wedge elements
/** TODO: Implementation in the nd-prism-dev branch */
class ND_WedgeDofTransformation : public ND_DofTransformation
{
public:
   ND_WedgeDofTransformation(int order);

   using DofTransformation::TransformPrimal;
   using DofTransformation::InvTransformPrimal;
   using DofTransformation::TransformDual;

   void TransformPrimal(const double *, double *) const;

   void InvTransformPrimal(const double *, double *) const;

   void TransformDual(const double *, double *) const;
};

} // namespace mfem

#endif // MFEM_DOFTRANSFORM
<|endoftext|>


<commit_before>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM 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) version 2.1 dated February 1999.

#ifndef MFEM_INTRULES
#define MFEM_INTRULES

#include "../config/config.hpp"
#include "../general/array.hpp"

namespace mfem
{

/* Classes for IntegrationPoint, IntegrationRule, and container class
   IntegrationRules.  Declares the global variable IntRules */

/// Class for integration point with weight
class IntegrationPoint
{
public:
   double x, y, z, weight;

   void Init() { x = y = z = weight = 0.0; }

   void Set(const double *p, const int dim)
   {
      MFEM_ASSERT(1 <= dim && dim <= 3, "invalid dim: " << dim);
      x = p[0];
      if (dim > 1)
      {
         y = p[1];
         if (dim > 2)
         {
            z = p[2];
         }
      }
   }

   void Get(double *p, const int dim) const
   {
      MFEM_ASSERT(1 <= dim && dim <= 3, "invalid dim: " << dim);
      p[0] = x;
      if (dim > 1)
      {
         p[1] = y;
         if (dim > 2)
         {
            p[2] = z;
         }
      }
   }

   void Set(const double x1, const double x2, const double x3, const double w)
   { x = x1; y = x2; z = x3; weight = w; }

   void Set3w(const double *p) { x = p[0]; y = p[1]; z = p[2]; weight = p[3]; }

   void Set3(const double x1, const double x2, const double x3)
   { x = x1; y = x2; z = x3; }

   void Set3(const double *p) { x = p[0]; y = p[1]; z = p[2]; }

   void Set2w(const double x1, const double x2, const double w)
   { x = x1; y = x2; weight = w; }

   void Set2w(const double *p) { x = p[0]; y = p[1]; weight = p[2]; }

   void Set2(const double x1, const double x2) { x = x1; y = x2; }

   void Set2(const double *p) { x = p[0]; y = p[1]; }

   void Set1w(const double x1, const double w) { x = x1; weight = w; }

   void Set1w(const double *p) { x = p[0]; weight = p[1]; }
};

/// Class for an integration rule - an Array of IntegrationPoint.
class IntegrationRule : public Array<IntegrationPoint>
{
private:
   friend class IntegrationRules;
   int Order;

   /// Define n-simplex rule (triangle/tetrahedron for n=2/3) of order (2s+1)
   void GrundmannMollerSimplexRule(int s, int n = 3);

   void AddTriMidPoint(const int off, const double weight)
   { IntPoint(off).Set2w(1./3., 1./3., weight); }

   void AddTriPoints3(const int off, const double a, const double b,
                      const double weight)
   {
      IntPoint(off + 0).Set2w(a, a, weight);
      IntPoint(off + 1).Set2w(a, b, weight);
      IntPoint(off + 2).Set2w(b, a, weight);
   }

   void AddTriPoints3(const int off, const double a, const double weight)
   { AddTriPoints3(off, a, 1. - 2.*a, weight); }

   void AddTriPoints3b(const int off, const double b, const double weight)
   { AddTriPoints3(off, (1. - b)/2., b, weight); }

   void AddTriPoints3R(const int off, const double a, const double b,
                       const double c, const double weight)
   {
      IntPoint(off + 0).Set2w(a, b, weight);
      IntPoint(off + 1).Set2w(c, a, weight);
      IntPoint(off + 2).Set2w(b, c, weight);
   }

   void AddTriPoints3R(const int off, const double a, const double b,
                       const double weight)
   { AddTriPoints3R(off, a, b, 1. - a - b, weight); }

   void AddTriPoints6(const int off, const double a, const double b,
                      const double c, const double weight)
   {
      IntPoint(off + 0).Set2w(a, b, weight);
      IntPoint(off + 1).Set2w(b, a, weight);
      IntPoint(off + 2).Set2w(a, c, weight);
      IntPoint(off + 3).Set2w(c, a, weight);
      IntPoint(off + 4).Set2w(b, c, weight);
      IntPoint(off + 5).Set2w(c, b, weight);
   }

   void AddTriPoints6(const int off, const double a, const double b,
                      const double weight)
   { AddTriPoints6(off, a, b, 1. - a - b, weight); }

   // add the permutations of (a,a,b)
   void AddTetPoints3(const int off, const double a, const double b,
                      const double weight)
   {
      IntPoint(off + 0).Set(a, a, b, weight);
      IntPoint(off + 1).Set(a, b, a, weight);
      IntPoint(off + 2).Set(b, a, a, weight);
   }

   // add the permutations of (a,b,c)
   void AddTetPoints6(const int off, const double a, const double b,
                      const double c, const double weight)
   {
      IntPoint(off + 0).Set(a, b, c, weight);
      IntPoint(off + 1).Set(a, c, b, weight);
      IntPoint(off + 2).Set(b, c, a, weight);
      IntPoint(off + 3).Set(b, a, c, weight);
      IntPoint(off + 4).Set(c, a, b, weight);
      IntPoint(off + 5).Set(c, b, a, weight);
   }

   void AddTetMidPoint(const int off, const double weight)
   { IntPoint(off).Set(0.25, 0.25, 0.25, weight); }

   // given a, add the permutations of (a,a,a,b), where 3*a + b = 1
   void AddTetPoints4(const int off, const double a, const double weight)
   {
      IntPoint(off).Set(a, a, a, weight);
      AddTetPoints3(off + 1, a, 1. - 3.*a, weight);
   }

   // given b, add the permutations of (a,a,a,b), where 3*a + b = 1
   void AddTetPoints4b(const int off, const double b, const double weight)
   {
      const double a = (1. - b)/3.;
      IntPoint(off).Set(a, a, a, weight);
      AddTetPoints3(off + 1, a, b, weight);
   }

   // add the permutations of (a,a,b,b), 2*(a + b) = 1
   void AddTetPoints6(const int off, const double a, const double weight)
   {
      const double b = 0.5 - a;
      AddTetPoints3(off,     a, b, weight);
      AddTetPoints3(off + 3, b, a, weight);
   }

   // given (a,b) or (a,c), add the permutations of (a,a,b,c), 2*a + b + c = 1
   void AddTetPoints12(const int off, const double a, const double bc,
                       const double weight)
   {
      const double cb = 1. - 2*a - bc;
      AddTetPoints3(off,     a, bc, weight);
      AddTetPoints3(off + 3, a, cb, weight);
      AddTetPoints6(off + 6, a, bc, cb, weight);
   }

   // given (b,c), add the permutations of (a,a,b,c), 2*a + b + c = 1
   void AddTetPoints12bc(const int off, const double b, const double c,
                         const double weight)
   {
      const double a = (1. - b - c)/2.;
      AddTetPoints3(off,     a, b, weight);
      AddTetPoints3(off + 3, a, c, weight);
      AddTetPoints6(off + 6, a, b, c, weight);
   }

public:
   IntegrationRule() :
      Array<IntegrationPoint>(), Order(0) { }

   /// Construct an integration rule with given number of points
   explicit IntegrationRule(int NP) :
      Array<IntegrationPoint>(NP), Order(0)
   {
      for (int i = 0; i < this->Size(); i++)
      {
         (*this)[i].Init();
      }
   }

   /// Tensor product of two 1D integration rules
   IntegrationRule(IntegrationRule &irx, IntegrationRule &iry);

   /// Tensor product of three 1D integration rules
   IntegrationRule(IntegrationRule &irx, IntegrationRule &iry,
                   IntegrationRule &irz);

   /// Returns the order of the integration rule
   int GetOrder() const { return Order; }

   /** @brief Sets the order of the integration rule. This is only for keeping
       order information, it does not alter any data in the IntegrationRule. */
   void SetOrder(const int order) { Order = order; }

   /// Returns the number of the points in the integration rule
   int GetNPoints() const { return Size(); }

   /// Returns a reference to the i-th integration point
   IntegrationPoint &IntPoint(int i) { return (*this)[i]; }

   /// Returns a const reference to the i-th integration point
   const IntegrationPoint &IntPoint(int i) const { return (*this)[i]; }

   /// Destroys an IntegrationRule object
   ~IntegrationRule() { }
};

/// A Class that defines 1-D numerical quadrature rules on [0,1].
class QuadratureFunctions1D
{
public:
   /** @name Methods for calculating quadrature rules.
       These methods calculate the actual points and weights for the different
       types of quadrature rules. */
   ///@{
   void GaussLegendre(const int np, IntegrationRule* ir);
   void GaussLobatto(const int np, IntegrationRule *ir);
   void OpenUniform(const int np, IntegrationRule *ir);
   void ClosedUniform(const int np, IntegrationRule *ir);
   void OpenHalfUniform(const int np, IntegrationRule *ir);
   ///@}

   /// A helper function that will play nice with Poly_1D::OpenPoints and
   /// Poly_1D::ClosedPoints
   void GivePolyPoints(const int np, double *pts, const int type);

private:
   void CalculateUniformWeights(IntegrationRule *ir, const int type);
};

/// A class container for 1D quadrature type constants.
class Quadrature1D
{
public:
   enum
   {
      Invalid         = -1,
      GaussLegendre   = 0,
      GaussLobatto    = 1,
      OpenUniform     = 2,  ///< aka open Newton-Cotes
      ClosedUniform   = 3,  ///< aka closed Newton-Cotes
      OpenHalfUniform = 4   ///< aka "open half" Newton-Cotes
   };
   /** @brief If the Quadrature1D type is not closed return Invalid; otherwise
       return type. */
   static int CheckClosed(int type);
   /** @brief If the Quadrature1D type is not open return Invalid; otherwise
       return type. */
   static int CheckOpen(int type);
};

/// Container class for integration rules
class IntegrationRules
{
private:
   /// Taken from the Quadrature1D class anonymous enum
   /// Determines the type of numerical quadrature used for
   /// segment, square, and cube geometries
   const int quad_type;

   int own_rules, refined;

   /// Function that generates quadrature points and weights on [0,1]
   QuadratureFunctions1D quad_func;

   Array<IntegrationRule *> PointIntRules;
   Array<IntegrationRule *> SegmentIntRules;
   Array<IntegrationRule *> TriangleIntRules;
   Array<IntegrationRule *> SquareIntRules;
   Array<IntegrationRule *> TetrahedronIntRules;
   Array<IntegrationRule *> PrismIntRules;
   Array<IntegrationRule *> CubeIntRules;

   void AllocIntRule(Array<IntegrationRule *> &ir_array, int Order)
   {
      if (ir_array.Size() <= Order)
      {
         ir_array.SetSize(Order + 1, NULL);
      }
   }
   bool HaveIntRule(Array<IntegrationRule *> &ir_array, int Order)
   {
      return (ir_array.Size() > Order && ir_array[Order] != NULL);
   }
   int GetSegmentRealOrder(int Order) const
   {
      return Order | 1; // valid for all quad_type's
   }

   IntegrationRule *GenerateIntegrationRule(int GeomType, int Order);
   IntegrationRule *PointIntegrationRule(int Order);
   IntegrationRule *SegmentIntegrationRule(int Order);
   IntegrationRule *TriangleIntegrationRule(int Order);
   IntegrationRule *SquareIntegrationRule(int Order);
   IntegrationRule *TetrahedronIntegrationRule(int Order);
   IntegrationRule *PrismIntegrationRule(int Order);
   IntegrationRule *CubeIntegrationRule(int Order);

   void DeleteIntRuleArray(Array<IntegrationRule *> &ir_array);

public:
   /// Sets initial sizes for the integration rule arrays, but rules
   /// are defined the first time they are requested with the Get method.
   explicit IntegrationRules(int Ref = 0,
                             int type = Quadrature1D::GaussLegendre);

   /// Returns an integration rule for given GeomType and Order.
   const IntegrationRule &Get(int GeomType, int Order);

   void Set(int GeomType, int Order, IntegrationRule &IntRule);

   void SetOwnRules(int o) { own_rules = o; }

   /// Destroys an IntegrationRules object
   ~IntegrationRules();
};

/// A global object with all integration rules (defined in intrules.cpp)
extern IntegrationRules IntRules;

/// A global object with all refined integration rules
extern IntegrationRules RefinedIntRules;

}

#endif
<commit_msg>Adding comment to direct developers to more appropriate method<commit_after>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM 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) version 2.1 dated February 1999.

#ifndef MFEM_INTRULES
#define MFEM_INTRULES

#include "../config/config.hpp"
#include "../general/array.hpp"

namespace mfem
{

/* Classes for IntegrationPoint, IntegrationRule, and container class
   IntegrationRules.  Declares the global variable IntRules */

/// Class for integration point with weight
class IntegrationPoint
{
public:
   double x, y, z, weight;

   void Init() { x = y = z = weight = 0.0; }

   void Set(const double *p, const int dim)
   {
      MFEM_ASSERT(1 <= dim && dim <= 3, "invalid dim: " << dim);
      x = p[0];
      if (dim > 1)
      {
         y = p[1];
         if (dim > 2)
         {
            z = p[2];
         }
      }
   }

   void Get(double *p, const int dim) const
   {
      MFEM_ASSERT(1 <= dim && dim <= 3, "invalid dim: " << dim);
      p[0] = x;
      if (dim > 1)
      {
         p[1] = y;
         if (dim > 2)
         {
            p[2] = z;
         }
      }
   }

   void Set(const double x1, const double x2, const double x3, const double w)
   { x = x1; y = x2; z = x3; weight = w; }

   void Set3w(const double *p) { x = p[0]; y = p[1]; z = p[2]; weight = p[3]; }

   void Set3(const double x1, const double x2, const double x3)
   { x = x1; y = x2; z = x3; }

   void Set3(const double *p) { x = p[0]; y = p[1]; z = p[2]; }

   void Set2w(const double x1, const double x2, const double w)
   { x = x1; y = x2; weight = w; }

   void Set2w(const double *p) { x = p[0]; y = p[1]; weight = p[2]; }

   void Set2(const double x1, const double x2) { x = x1; y = x2; }

   void Set2(const double *p) { x = p[0]; y = p[1]; }

   void Set1w(const double x1, const double w) { x = x1; weight = w; }

   void Set1w(const double *p) { x = p[0]; weight = p[1]; }
};

/// Class for an integration rule - an Array of IntegrationPoint.
class IntegrationRule : public Array<IntegrationPoint>
{
private:
   friend class IntegrationRules;
   int Order;

   /// Define n-simplex rule (triangle/tetrahedron for n=2/3) of order (2s+1)
   void GrundmannMollerSimplexRule(int s, int n = 3);

   void AddTriMidPoint(const int off, const double weight)
   { IntPoint(off).Set2w(1./3., 1./3., weight); }

   void AddTriPoints3(const int off, const double a, const double b,
                      const double weight)
   {
      IntPoint(off + 0).Set2w(a, a, weight);
      IntPoint(off + 1).Set2w(a, b, weight);
      IntPoint(off + 2).Set2w(b, a, weight);
   }

   void AddTriPoints3(const int off, const double a, const double weight)
   { AddTriPoints3(off, a, 1. - 2.*a, weight); }

   void AddTriPoints3b(const int off, const double b, const double weight)
   { AddTriPoints3(off, (1. - b)/2., b, weight); }

   void AddTriPoints3R(const int off, const double a, const double b,
                       const double c, const double weight)
   {
      IntPoint(off + 0).Set2w(a, b, weight);
      IntPoint(off + 1).Set2w(c, a, weight);
      IntPoint(off + 2).Set2w(b, c, weight);
   }

   void AddTriPoints3R(const int off, const double a, const double b,
                       const double weight)
   { AddTriPoints3R(off, a, b, 1. - a - b, weight); }

   void AddTriPoints6(const int off, const double a, const double b,
                      const double c, const double weight)
   {
      IntPoint(off + 0).Set2w(a, b, weight);
      IntPoint(off + 1).Set2w(b, a, weight);
      IntPoint(off + 2).Set2w(a, c, weight);
      IntPoint(off + 3).Set2w(c, a, weight);
      IntPoint(off + 4).Set2w(b, c, weight);
      IntPoint(off + 5).Set2w(c, b, weight);
   }

   void AddTriPoints6(const int off, const double a, const double b,
                      const double weight)
   { AddTriPoints6(off, a, b, 1. - a - b, weight); }

   // add the permutations of (a,a,b)
   void AddTetPoints3(const int off, const double a, const double b,
                      const double weight)
   {
      IntPoint(off + 0).Set(a, a, b, weight);
      IntPoint(off + 1).Set(a, b, a, weight);
      IntPoint(off + 2).Set(b, a, a, weight);
   }

   // add the permutations of (a,b,c)
   void AddTetPoints6(const int off, const double a, const double b,
                      const double c, const double weight)
   {
      IntPoint(off + 0).Set(a, b, c, weight);
      IntPoint(off + 1).Set(a, c, b, weight);
      IntPoint(off + 2).Set(b, c, a, weight);
      IntPoint(off + 3).Set(b, a, c, weight);
      IntPoint(off + 4).Set(c, a, b, weight);
      IntPoint(off + 5).Set(c, b, a, weight);
   }

   void AddTetMidPoint(const int off, const double weight)
   { IntPoint(off).Set(0.25, 0.25, 0.25, weight); }

   // given a, add the permutations of (a,a,a,b), where 3*a + b = 1
   void AddTetPoints4(const int off, const double a, const double weight)
   {
      IntPoint(off).Set(a, a, a, weight);
      AddTetPoints3(off + 1, a, 1. - 3.*a, weight);
   }

   // given b, add the permutations of (a,a,a,b), where 3*a + b = 1
   void AddTetPoints4b(const int off, const double b, const double weight)
   {
      const double a = (1. - b)/3.;
      IntPoint(off).Set(a, a, a, weight);
      AddTetPoints3(off + 1, a, b, weight);
   }

   // add the permutations of (a,a,b,b), 2*(a + b) = 1
   void AddTetPoints6(const int off, const double a, const double weight)
   {
      const double b = 0.5 - a;
      AddTetPoints3(off,     a, b, weight);
      AddTetPoints3(off + 3, b, a, weight);
   }

   // given (a,b) or (a,c), add the permutations of (a,a,b,c), 2*a + b + c = 1
   void AddTetPoints12(const int off, const double a, const double bc,
                       const double weight)
   {
      const double cb = 1. - 2*a - bc;
      AddTetPoints3(off,     a, bc, weight);
      AddTetPoints3(off + 3, a, cb, weight);
      AddTetPoints6(off + 6, a, bc, cb, weight);
   }

   // given (b,c), add the permutations of (a,a,b,c), 2*a + b + c = 1
   void AddTetPoints12bc(const int off, const double b, const double c,
                         const double weight)
   {
      const double a = (1. - b - c)/2.;
      AddTetPoints3(off,     a, b, weight);
      AddTetPoints3(off + 3, a, c, weight);
      AddTetPoints6(off + 6, a, b, c, weight);
   }

public:
   IntegrationRule() :
      Array<IntegrationPoint>(), Order(0) { }

   /// Construct an integration rule with given number of points
   explicit IntegrationRule(int NP) :
      Array<IntegrationPoint>(NP), Order(0)
   {
      for (int i = 0; i < this->Size(); i++)
      {
         (*this)[i].Init();
      }
   }

   /// Tensor product of two 1D integration rules
   IntegrationRule(IntegrationRule &irx, IntegrationRule &iry);

   /// Tensor product of three 1D integration rules
   IntegrationRule(IntegrationRule &irx, IntegrationRule &iry,
                   IntegrationRule &irz);

   /// Returns the order of the integration rule
   int GetOrder() const { return Order; }

   /** @brief Sets the order of the integration rule. This is only for keeping
       order information, it does not alter any data in the IntegrationRule. */
   void SetOrder(const int order) { Order = order; }

   /// Returns the number of the points in the integration rule
   int GetNPoints() const { return Size(); }

   /// Returns a reference to the i-th integration point
   IntegrationPoint &IntPoint(int i) { return (*this)[i]; }

   /// Returns a const reference to the i-th integration point
   const IntegrationPoint &IntPoint(int i) const { return (*this)[i]; }

   /// Destroys an IntegrationRule object
   ~IntegrationRule() { }
};

/// A Class that defines 1-D numerical quadrature rules on [0,1].
class QuadratureFunctions1D
{
public:
   /** @name Methods for calculating quadrature rules.
       These methods calculate the actual points and weights for the different
       types of quadrature rules. */
   ///@{
   void GaussLegendre(const int np, IntegrationRule* ir);
   void GaussLobatto(const int np, IntegrationRule *ir);
   void OpenUniform(const int np, IntegrationRule *ir);
   void ClosedUniform(const int np, IntegrationRule *ir);
   void OpenHalfUniform(const int np, IntegrationRule *ir);
   ///@}

   /// A helper function that will play nice with Poly_1D::OpenPoints and
   /// Poly_1D::ClosedPoints
   void GivePolyPoints(const int np, double *pts, const int type);

private:
   void CalculateUniformWeights(IntegrationRule *ir, const int type);
};

/// A class container for 1D quadrature type constants.
class Quadrature1D
{
public:
   enum
   {
      Invalid         = -1,
      GaussLegendre   = 0,
      GaussLobatto    = 1,
      OpenUniform     = 2,  ///< aka open Newton-Cotes
      ClosedUniform   = 3,  ///< aka closed Newton-Cotes
      OpenHalfUniform = 4   ///< aka "open half" Newton-Cotes
   };
   /** @brief If the Quadrature1D type is not closed return Invalid; otherwise
       return type. */
   static int CheckClosed(int type);
   /** @brief If the Quadrature1D type is not open return Invalid; otherwise
       return type. */
   static int CheckOpen(int type);
};

/// Container class for integration rules
class IntegrationRules
{
private:
   /// Taken from the Quadrature1D class anonymous enum
   /// Determines the type of numerical quadrature used for
   /// segment, square, and cube geometries
   const int quad_type;

   int own_rules, refined;

   /// Function that generates quadrature points and weights on [0,1]
   QuadratureFunctions1D quad_func;

   Array<IntegrationRule *> PointIntRules;
   Array<IntegrationRule *> SegmentIntRules;
   Array<IntegrationRule *> TriangleIntRules;
   Array<IntegrationRule *> SquareIntRules;
   Array<IntegrationRule *> TetrahedronIntRules;
   Array<IntegrationRule *> PrismIntRules;
   Array<IntegrationRule *> CubeIntRules;

   void AllocIntRule(Array<IntegrationRule *> &ir_array, int Order)
   {
      if (ir_array.Size() <= Order)
      {
         ir_array.SetSize(Order + 1, NULL);
      }
   }
   bool HaveIntRule(Array<IntegrationRule *> &ir_array, int Order)
   {
      return (ir_array.Size() > Order && ir_array[Order] != NULL);
   }
   int GetSegmentRealOrder(int Order) const
   {
      return Order | 1; // valid for all quad_type's
   }

   /// The following methods allocate new IntegrationRule objects without
   /// checking if they already exist.  To avoid memory leaks use
   /// IntegrationRules::Get(int GeomType, int Order) instead.
   IntegrationRule *GenerateIntegrationRule(int GeomType, int Order);
   IntegrationRule *PointIntegrationRule(int Order);
   IntegrationRule *SegmentIntegrationRule(int Order);
   IntegrationRule *TriangleIntegrationRule(int Order);
   IntegrationRule *SquareIntegrationRule(int Order);
   IntegrationRule *TetrahedronIntegrationRule(int Order);
   IntegrationRule *PrismIntegrationRule(int Order);
   IntegrationRule *CubeIntegrationRule(int Order);

   void DeleteIntRuleArray(Array<IntegrationRule *> &ir_array);

public:
   /// Sets initial sizes for the integration rule arrays, but rules
   /// are defined the first time they are requested with the Get method.
   explicit IntegrationRules(int Ref = 0,
                             int type = Quadrature1D::GaussLegendre);

   /// Returns an integration rule for given GeomType and Order.
   const IntegrationRule &Get(int GeomType, int Order);

   void Set(int GeomType, int Order, IntegrationRule &IntRule);

   void SetOwnRules(int o) { own_rules = o; }

   /// Destroys an IntegrationRules object
   ~IntegrationRules();
};

/// A global object with all integration rules (defined in intrules.cpp)
extern IntegrationRules IntRules;

/// A global object with all refined integration rules
extern IntegrationRules RefinedIntRules;

}

#endif
<|endoftext|>