<commit_before>//===-- UnrollLoop.cpp - Loop unrolling utilities -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements some loop unrolling utilities. It does not define any
// actual pass or policy, but provides a single function to perform loop
// unrolling.
//
// It works best when loops have been canonicalized by the -indvars pass,
// allowing it to determine the trip counts of loops easily.
//
// The process of unrolling can produce extraneous basic blocks linked with
// unconditional branches.  This will be corrected in the future.
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "loop-unroll"
#include "llvm/Transforms/Utils/UnrollLoop.h"
#include "llvm/BasicBlock.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Local.h"
#include <cstdio>

using namespace llvm;

// TODO: Should these be here or in LoopUnroll?
STATISTIC(NumCompletelyUnrolled, "Number of loops completely unrolled");
STATISTIC(NumUnrolled,    "Number of loops unrolled (completely or otherwise)");

/// RemapInstruction - Convert the instruction operands from referencing the
/// current values into those specified by ValueMap.
static inline void RemapInstruction(Instruction *I,
                                    DenseMap<const Value *, Value*> &ValueMap) {
  for (unsigned op = 0, E = I->getNumOperands(); op != E; ++op) {
    Value *Op = I->getOperand(op);
    DenseMap<const Value *, Value*>::iterator It = ValueMap.find(Op);
    if (It != ValueMap.end())
      I->setOperand(op, It->second);
  }
}

/// FoldBlockIntoPredecessor - Folds a basic block into its predecessor if it
/// only has one predecessor, and that predecessor only has one successor.
/// The LoopInfo Analysis that is passed will be kept consistent.
/// Returns the new combined block.
static BasicBlock *FoldBlockIntoPredecessor(BasicBlock *BB, LoopInfo* LI) {
  // Merge basic blocks into their predecessor if there is only one distinct
  // pred, and if there is only one distinct successor of the predecessor, and
  // if there are no PHI nodes.
  BasicBlock *OnlyPred = BB->getSinglePredecessor();
  if (!OnlyPred) return 0;

  if (OnlyPred->getTerminator()->getNumSuccessors() != 1)
    return 0;

  DEBUG(errs() << "Merging: " << *BB << "into: " << *OnlyPred);

  // Resolve any PHI nodes at the start of the block.  They are all
  // guaranteed to have exactly one entry if they exist, unless there are
  // multiple duplicate (but guaranteed to be equal) entries for the
  // incoming edges.  This occurs when there are multiple edges from
  // OnlyPred to OnlySucc.
  FoldSingleEntryPHINodes(BB);

  // Delete the unconditional branch from the predecessor...
  OnlyPred->getInstList().pop_back();

  // Move all definitions in the successor to the predecessor...
  OnlyPred->getInstList().splice(OnlyPred->end(), BB->getInstList());

  // Make all PHI nodes that referred to BB now refer to Pred as their
  // source...
  BB->replaceAllUsesWith(OnlyPred);

  std::string OldName = BB->getName();

  // Erase basic block from the function...
  LI->removeBlock(BB);
  BB->eraseFromParent();

  // Inherit predecessor's name if it exists...
  if (!OldName.empty() && !OnlyPred->hasName())
    OnlyPred->setName(OldName);

  return OnlyPred;
}

/// Unroll the given loop by Count. The loop must be in LCSSA form. Returns true
/// if unrolling was succesful, or false if the loop was unmodified. Unrolling
/// can only fail when the loop's latch block is not terminated by a conditional
/// branch instruction. However, if the trip count (and multiple) are not known,
/// loop unrolling will mostly produce more code that is no faster.
///
/// The LoopInfo Analysis that is passed will be kept consistent.
///
/// If a LoopPassManager is passed in, and the loop is fully removed, it will be
/// removed from the LoopPassManager as well. LPM can also be NULL.
bool llvm::UnrollLoop(Loop *L, unsigned Count, LoopInfo* LI, LPPassManager* LPM) {
  assert(L->isLCSSAForm());

  BasicBlock *Header = L->getHeader();
  BasicBlock *LatchBlock = L->getLoopLatch();
  BranchInst *BI = dyn_cast<BranchInst>(LatchBlock->getTerminator());

  if (!BI || BI->isUnconditional()) {
    // The loop-rotate pass can be helpful to avoid this in many cases.
    DEBUG(errs() <<
             "  Can't unroll; loop not terminated by a conditional branch.\n");
    return false;
  }

  // Find trip count
  unsigned TripCount = L->getSmallConstantTripCount();
  // Find trip multiple if count is not available
  unsigned TripMultiple = 1;
  if (TripCount == 0)
    TripMultiple = L->getSmallConstantTripMultiple();

  if (TripCount != 0)
    DEBUG(errs() << "  Trip Count = " << TripCount << "\n");
  if (TripMultiple != 1)
    DEBUG(errs() << "  Trip Multiple = " << TripMultiple << "\n");

  // Effectively "DCE" unrolled iterations that are beyond the tripcount
  // and will never be executed.
  if (TripCount != 0 && Count > TripCount)
    Count = TripCount;

  assert(Count > 0);
  assert(TripMultiple > 0);
  assert(TripCount == 0 || TripCount % TripMultiple == 0);

  // Are we eliminating the loop control altogether?
  bool CompletelyUnroll = Count == TripCount;

  // If we know the trip count, we know the multiple...
  unsigned BreakoutTrip = 0;
  if (TripCount != 0) {
    BreakoutTrip = TripCount % Count;
    TripMultiple = 0;
  } else {
    // Figure out what multiple to use.
    BreakoutTrip = TripMultiple =
      (unsigned)GreatestCommonDivisor64(Count, TripMultiple);
  }

  if (CompletelyUnroll) {
    DEBUG(errs() << "COMPLETELY UNROLLING loop %" << Header->getName()
          << " with trip count " << TripCount << "!\n");
  } else {
    DEBUG(errs() << "UNROLLING loop %" << Header->getName()
          << " by " << Count);
    if (TripMultiple == 0 || BreakoutTrip != TripMultiple) {
      DEBUG(errs() << " with a breakout at trip " << BreakoutTrip);
    } else if (TripMultiple != 1) {
      DEBUG(errs() << " with " << TripMultiple << " trips per branch");
    }
    DEBUG(errs() << "!\n");
  }

  std::vector<BasicBlock*> LoopBlocks = L->getBlocks();

  bool ContinueOnTrue = L->contains(BI->getSuccessor(0));
  BasicBlock *LoopExit = BI->getSuccessor(ContinueOnTrue);

  // For the first iteration of the loop, we should use the precloned values for
  // PHI nodes.  Insert associations now.
  typedef DenseMap<const Value*, Value*> ValueMapTy;
  ValueMapTy LastValueMap;
  std::vector<PHINode*> OrigPHINode;
  for (BasicBlock::iterator I = Header->begin(); isa<PHINode>(I); ++I) {
    PHINode *PN = cast<PHINode>(I);
    OrigPHINode.push_back(PN);
    if (Instruction *I =
                dyn_cast<Instruction>(PN->getIncomingValueForBlock(LatchBlock)))
      if (L->contains(I->getParent()))
        LastValueMap[I] = I;
  }

  std::vector<BasicBlock*> Headers;
  std::vector<BasicBlock*> Latches;
  Headers.push_back(Header);
  Latches.push_back(LatchBlock);

  for (unsigned It = 1; It != Count; ++It) {
    char SuffixBuffer[100];
    sprintf(SuffixBuffer, ".%d", It);

    std::vector<BasicBlock*> NewBlocks;

    for (std::vector<BasicBlock*>::iterator BB = LoopBlocks.begin(),
         E = LoopBlocks.end(); BB != E; ++BB) {
      ValueMapTy ValueMap;
      BasicBlock *New = CloneBasicBlock(*BB, ValueMap, SuffixBuffer);
      Header->getParent()->getBasicBlockList().push_back(New);

      // Loop over all of the PHI nodes in the block, changing them to use the
      // incoming values from the previous block.
      if (*BB == Header)
        for (unsigned i = 0, e = OrigPHINode.size(); i != e; ++i) {
          PHINode *NewPHI = cast<PHINode>(ValueMap[OrigPHINode[i]]);
          Value *InVal = NewPHI->getIncomingValueForBlock(LatchBlock);
          if (Instruction *InValI = dyn_cast<Instruction>(InVal))
            if (It > 1 && L->contains(InValI->getParent()))
              InVal = LastValueMap[InValI];
          ValueMap[OrigPHINode[i]] = InVal;
          New->getInstList().erase(NewPHI);
        }

      // Update our running map of newest clones
      LastValueMap[*BB] = New;
      for (ValueMapTy::iterator VI = ValueMap.begin(), VE = ValueMap.end();
           VI != VE; ++VI)
        LastValueMap[VI->first] = VI->second;

      L->addBasicBlockToLoop(New, LI->getBase());

      // Add phi entries for newly created values to all exit blocks except
      // the successor of the latch block.  The successor of the exit block will
      // be updated specially after unrolling all the way.
      if (*BB != LatchBlock)
        for (Value::use_iterator UI = (*BB)->use_begin(), UE = (*BB)->use_end();
             UI != UE;) {
          Instruction *UseInst = cast<Instruction>(*UI);
          ++UI;
          if (isa<PHINode>(UseInst) && !L->contains(UseInst->getParent())) {
            PHINode *phi = cast<PHINode>(UseInst);
            Value *Incoming = phi->getIncomingValueForBlock(*BB);
            phi->addIncoming(Incoming, New);
          }
        }

      // Keep track of new headers and latches as we create them, so that
      // we can insert the proper branches later.
      if (*BB == Header)
        Headers.push_back(New);
      if (*BB == LatchBlock) {
        Latches.push_back(New);

        // Also, clear out the new latch's back edge so that it doesn't look
        // like a new loop, so that it's amenable to being merged with adjacent
        // blocks later on.
        TerminatorInst *Term = New->getTerminator();
        assert(L->contains(Term->getSuccessor(!ContinueOnTrue)));
        assert(Term->getSuccessor(ContinueOnTrue) == LoopExit);
        Term->setSuccessor(!ContinueOnTrue, NULL);
      }

      NewBlocks.push_back(New);
    }

    // Remap all instructions in the most recent iteration
    for (unsigned i = 0; i < NewBlocks.size(); ++i)
      for (BasicBlock::iterator I = NewBlocks[i]->begin(),
           E = NewBlocks[i]->end(); I != E; ++I)
        RemapInstruction(I, LastValueMap);
  }

  // The latch block exits the loop.  If there are any PHI nodes in the
  // successor blocks, update them to use the appropriate values computed as the
  // last iteration of the loop.
  if (Count != 1) {
    SmallPtrSet<PHINode*, 8> Users;
    for (Value::use_iterator UI = LatchBlock->use_begin(),
         UE = LatchBlock->use_end(); UI != UE; ++UI)
      if (PHINode *phi = dyn_cast<PHINode>(*UI))
        Users.insert(phi);

    BasicBlock *LastIterationBB = cast<BasicBlock>(LastValueMap[LatchBlock]);
    for (SmallPtrSet<PHINode*,8>::iterator SI = Users.begin(), SE = Users.end();
         SI != SE; ++SI) {
      PHINode *PN = *SI;
      Value *InVal = PN->removeIncomingValue(LatchBlock, false);
      // If this value was defined in the loop, take the value defined by the
      // last iteration of the loop.
      if (Instruction *InValI = dyn_cast<Instruction>(InVal)) {
        if (L->contains(InValI->getParent()))
          InVal = LastValueMap[InVal];
      }
      PN->addIncoming(InVal, LastIterationBB);
    }
  }

  // Now, if we're doing complete unrolling, loop over the PHI nodes in the
  // original block, setting them to their incoming values.
  if (CompletelyUnroll) {
    BasicBlock *Preheader = L->getLoopPreheader();
    for (unsigned i = 0, e = OrigPHINode.size(); i != e; ++i) {
      PHINode *PN = OrigPHINode[i];
      PN->replaceAllUsesWith(PN->getIncomingValueForBlock(Preheader));
      Header->getInstList().erase(PN);
    }
  }

  // Now that all the basic blocks for the unrolled iterations are in place,
  // set up the branches to connect them.
  for (unsigned i = 0, e = Latches.size(); i != e; ++i) {
    // The original branch was replicated in each unrolled iteration.
    BranchInst *Term = cast<BranchInst>(Latches[i]->getTerminator());

    // The branch destination.
    unsigned j = (i + 1) % e;
    BasicBlock *Dest = Headers[j];
    bool NeedConditional = true;

    // For a complete unroll, make the last iteration end with a branch
    // to the exit block.
    if (CompletelyUnroll && j == 0) {
      Dest = LoopExit;
      NeedConditional = false;
    }

    // If we know the trip count or a multiple of it, we can safely use an
    // unconditional branch for some iterations.
    if (j != BreakoutTrip && (TripMultiple == 0 || j % TripMultiple != 0)) {
      NeedConditional = false;
    }

    if (NeedConditional) {
      // Update the conditional branch's successor for the following
      // iteration.
      Term->setSuccessor(!ContinueOnTrue, Dest);
    } else {
      Term->setUnconditionalDest(Dest);
      // Merge adjacent basic blocks, if possible.
      if (BasicBlock *Fold = FoldBlockIntoPredecessor(Dest, LI)) {
        std::replace(Latches.begin(), Latches.end(), Dest, Fold);
        std::replace(Headers.begin(), Headers.end(), Dest, Fold);
      }
    }
  }

  // At this point, the code is well formed.  We now do a quick sweep over the
  // inserted code, doing constant propagation and dead code elimination as we
  // go.
  const std::vector<BasicBlock*> &NewLoopBlocks = L->getBlocks();
  for (std::vector<BasicBlock*>::const_iterator BB = NewLoopBlocks.begin(),
       BBE = NewLoopBlocks.end(); BB != BBE; ++BB)
    for (BasicBlock::iterator I = (*BB)->begin(), E = (*BB)->end(); I != E; ) {
      Instruction *Inst = I++;

      if (isInstructionTriviallyDead(Inst))
        (*BB)->getInstList().erase(Inst);
      else if (Constant *C = ConstantFoldInstruction(Inst,
                                                     Header->getContext())) {
        Inst->replaceAllUsesWith(C);
        (*BB)->getInstList().erase(Inst);
      }
    }

  NumCompletelyUnrolled += CompletelyUnroll;
  ++NumUnrolled;
  // Remove the loop from the LoopPassManager if it's completely removed.
  if (CompletelyUnroll && LPM != NULL)
    LPM->deleteLoopFromQueue(L);

  // If we didn't completely unroll the loop, it should still be in LCSSA form.
  if (!CompletelyUnroll)
    assert(L->isLCSSAForm());

  return true;
}
<commit_msg>Teach LoopUnroll how to bail if LoopSimplify can't give it what it needs.<commit_after>//===-- UnrollLoop.cpp - Loop unrolling utilities -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements some loop unrolling utilities. It does not define any
// actual pass or policy, but provides a single function to perform loop
// unrolling.
//
// It works best when loops have been canonicalized by the -indvars pass,
// allowing it to determine the trip counts of loops easily.
//
// The process of unrolling can produce extraneous basic blocks linked with
// unconditional branches.  This will be corrected in the future.
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "loop-unroll"
#include "llvm/Transforms/Utils/UnrollLoop.h"
#include "llvm/BasicBlock.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Local.h"
#include <cstdio>

using namespace llvm;

// TODO: Should these be here or in LoopUnroll?
STATISTIC(NumCompletelyUnrolled, "Number of loops completely unrolled");
STATISTIC(NumUnrolled,    "Number of loops unrolled (completely or otherwise)");

/// RemapInstruction - Convert the instruction operands from referencing the
/// current values into those specified by ValueMap.
static inline void RemapInstruction(Instruction *I,
                                    DenseMap<const Value *, Value*> &ValueMap) {
  for (unsigned op = 0, E = I->getNumOperands(); op != E; ++op) {
    Value *Op = I->getOperand(op);
    DenseMap<const Value *, Value*>::iterator It = ValueMap.find(Op);
    if (It != ValueMap.end())
      I->setOperand(op, It->second);
  }
}

/// FoldBlockIntoPredecessor - Folds a basic block into its predecessor if it
/// only has one predecessor, and that predecessor only has one successor.
/// The LoopInfo Analysis that is passed will be kept consistent.
/// Returns the new combined block.
static BasicBlock *FoldBlockIntoPredecessor(BasicBlock *BB, LoopInfo* LI) {
  // Merge basic blocks into their predecessor if there is only one distinct
  // pred, and if there is only one distinct successor of the predecessor, and
  // if there are no PHI nodes.
  BasicBlock *OnlyPred = BB->getSinglePredecessor();
  if (!OnlyPred) return 0;

  if (OnlyPred->getTerminator()->getNumSuccessors() != 1)
    return 0;

  DEBUG(errs() << "Merging: " << *BB << "into: " << *OnlyPred);

  // Resolve any PHI nodes at the start of the block.  They are all
  // guaranteed to have exactly one entry if they exist, unless there are
  // multiple duplicate (but guaranteed to be equal) entries for the
  // incoming edges.  This occurs when there are multiple edges from
  // OnlyPred to OnlySucc.
  FoldSingleEntryPHINodes(BB);

  // Delete the unconditional branch from the predecessor...
  OnlyPred->getInstList().pop_back();

  // Move all definitions in the successor to the predecessor...
  OnlyPred->getInstList().splice(OnlyPred->end(), BB->getInstList());

  // Make all PHI nodes that referred to BB now refer to Pred as their
  // source...
  BB->replaceAllUsesWith(OnlyPred);

  std::string OldName = BB->getName();

  // Erase basic block from the function...
  LI->removeBlock(BB);
  BB->eraseFromParent();

  // Inherit predecessor's name if it exists...
  if (!OldName.empty() && !OnlyPred->hasName())
    OnlyPred->setName(OldName);

  return OnlyPred;
}

/// Unroll the given loop by Count. The loop must be in LCSSA form. Returns true
/// if unrolling was succesful, or false if the loop was unmodified. Unrolling
/// can only fail when the loop's latch block is not terminated by a conditional
/// branch instruction. However, if the trip count (and multiple) are not known,
/// loop unrolling will mostly produce more code that is no faster.
///
/// The LoopInfo Analysis that is passed will be kept consistent.
///
/// If a LoopPassManager is passed in, and the loop is fully removed, it will be
/// removed from the LoopPassManager as well. LPM can also be NULL.
bool llvm::UnrollLoop(Loop *L, unsigned Count, LoopInfo* LI, LPPassManager* LPM) {
  assert(L->isLCSSAForm());

  BasicBlock *Preheader = L->getLoopPreheader();
  if (!Preheader) {
    DEBUG(errs() << "  Can't unroll; loop preheader-insertion failed.\n");
    return false;
  }

  BasicBlock *LatchBlock = L->getLoopLatch();
  if (!LatchBlock) {
    DEBUG(errs() << "  Can't unroll; loop exit-block-insertion failed.\n");
    return false;
  }

  BasicBlock *Header = L->getHeader();
  BranchInst *BI = dyn_cast<BranchInst>(LatchBlock->getTerminator());

  if (!BI || BI->isUnconditional()) {
    // The loop-rotate pass can be helpful to avoid this in many cases.
    DEBUG(errs() <<
             "  Can't unroll; loop not terminated by a conditional branch.\n");
    return false;
  }

  // Find trip count
  unsigned TripCount = L->getSmallConstantTripCount();
  // Find trip multiple if count is not available
  unsigned TripMultiple = 1;
  if (TripCount == 0)
    TripMultiple = L->getSmallConstantTripMultiple();

  if (TripCount != 0)
    DEBUG(errs() << "  Trip Count = " << TripCount << "\n");
  if (TripMultiple != 1)
    DEBUG(errs() << "  Trip Multiple = " << TripMultiple << "\n");

  // Effectively "DCE" unrolled iterations that are beyond the tripcount
  // and will never be executed.
  if (TripCount != 0 && Count > TripCount)
    Count = TripCount;

  assert(Count > 0);
  assert(TripMultiple > 0);
  assert(TripCount == 0 || TripCount % TripMultiple == 0);

  // Are we eliminating the loop control altogether?
  bool CompletelyUnroll = Count == TripCount;

  // If we know the trip count, we know the multiple...
  unsigned BreakoutTrip = 0;
  if (TripCount != 0) {
    BreakoutTrip = TripCount % Count;
    TripMultiple = 0;
  } else {
    // Figure out what multiple to use.
    BreakoutTrip = TripMultiple =
      (unsigned)GreatestCommonDivisor64(Count, TripMultiple);
  }

  if (CompletelyUnroll) {
    DEBUG(errs() << "COMPLETELY UNROLLING loop %" << Header->getName()
          << " with trip count " << TripCount << "!\n");
  } else {
    DEBUG(errs() << "UNROLLING loop %" << Header->getName()
          << " by " << Count);
    if (TripMultiple == 0 || BreakoutTrip != TripMultiple) {
      DEBUG(errs() << " with a breakout at trip " << BreakoutTrip);
    } else if (TripMultiple != 1) {
      DEBUG(errs() << " with " << TripMultiple << " trips per branch");
    }
    DEBUG(errs() << "!\n");
  }

  std::vector<BasicBlock*> LoopBlocks = L->getBlocks();

  bool ContinueOnTrue = L->contains(BI->getSuccessor(0));
  BasicBlock *LoopExit = BI->getSuccessor(ContinueOnTrue);

  // For the first iteration of the loop, we should use the precloned values for
  // PHI nodes.  Insert associations now.
  typedef DenseMap<const Value*, Value*> ValueMapTy;
  ValueMapTy LastValueMap;
  std::vector<PHINode*> OrigPHINode;
  for (BasicBlock::iterator I = Header->begin(); isa<PHINode>(I); ++I) {
    PHINode *PN = cast<PHINode>(I);
    OrigPHINode.push_back(PN);
    if (Instruction *I =
                dyn_cast<Instruction>(PN->getIncomingValueForBlock(LatchBlock)))
      if (L->contains(I->getParent()))
        LastValueMap[I] = I;
  }

  std::vector<BasicBlock*> Headers;
  std::vector<BasicBlock*> Latches;
  Headers.push_back(Header);
  Latches.push_back(LatchBlock);

  for (unsigned It = 1; It != Count; ++It) {
    char SuffixBuffer[100];
    sprintf(SuffixBuffer, ".%d", It);

    std::vector<BasicBlock*> NewBlocks;

    for (std::vector<BasicBlock*>::iterator BB = LoopBlocks.begin(),
         E = LoopBlocks.end(); BB != E; ++BB) {
      ValueMapTy ValueMap;
      BasicBlock *New = CloneBasicBlock(*BB, ValueMap, SuffixBuffer);
      Header->getParent()->getBasicBlockList().push_back(New);

      // Loop over all of the PHI nodes in the block, changing them to use the
      // incoming values from the previous block.
      if (*BB == Header)
        for (unsigned i = 0, e = OrigPHINode.size(); i != e; ++i) {
          PHINode *NewPHI = cast<PHINode>(ValueMap[OrigPHINode[i]]);
          Value *InVal = NewPHI->getIncomingValueForBlock(LatchBlock);
          if (Instruction *InValI = dyn_cast<Instruction>(InVal))
            if (It > 1 && L->contains(InValI->getParent()))
              InVal = LastValueMap[InValI];
          ValueMap[OrigPHINode[i]] = InVal;
          New->getInstList().erase(NewPHI);
        }

      // Update our running map of newest clones
      LastValueMap[*BB] = New;
      for (ValueMapTy::iterator VI = ValueMap.begin(), VE = ValueMap.end();
           VI != VE; ++VI)
        LastValueMap[VI->first] = VI->second;

      L->addBasicBlockToLoop(New, LI->getBase());

      // Add phi entries for newly created values to all exit blocks except
      // the successor of the latch block.  The successor of the exit block will
      // be updated specially after unrolling all the way.
      if (*BB != LatchBlock)
        for (Value::use_iterator UI = (*BB)->use_begin(), UE = (*BB)->use_end();
             UI != UE;) {
          Instruction *UseInst = cast<Instruction>(*UI);
          ++UI;
          if (isa<PHINode>(UseInst) && !L->contains(UseInst->getParent())) {
            PHINode *phi = cast<PHINode>(UseInst);
            Value *Incoming = phi->getIncomingValueForBlock(*BB);
            phi->addIncoming(Incoming, New);
          }
        }

      // Keep track of new headers and latches as we create them, so that
      // we can insert the proper branches later.
      if (*BB == Header)
        Headers.push_back(New);
      if (*BB == LatchBlock) {
        Latches.push_back(New);

        // Also, clear out the new latch's back edge so that it doesn't look
        // like a new loop, so that it's amenable to being merged with adjacent
        // blocks later on.
        TerminatorInst *Term = New->getTerminator();
        assert(L->contains(Term->getSuccessor(!ContinueOnTrue)));
        assert(Term->getSuccessor(ContinueOnTrue) == LoopExit);
        Term->setSuccessor(!ContinueOnTrue, NULL);
      }

      NewBlocks.push_back(New);
    }

    // Remap all instructions in the most recent iteration
    for (unsigned i = 0; i < NewBlocks.size(); ++i)
      for (BasicBlock::iterator I = NewBlocks[i]->begin(),
           E = NewBlocks[i]->end(); I != E; ++I)
        RemapInstruction(I, LastValueMap);
  }

  // The latch block exits the loop.  If there are any PHI nodes in the
  // successor blocks, update them to use the appropriate values computed as the
  // last iteration of the loop.
  if (Count != 1) {
    SmallPtrSet<PHINode*, 8> Users;
    for (Value::use_iterator UI = LatchBlock->use_begin(),
         UE = LatchBlock->use_end(); UI != UE; ++UI)
      if (PHINode *phi = dyn_cast<PHINode>(*UI))
        Users.insert(phi);

    BasicBlock *LastIterationBB = cast<BasicBlock>(LastValueMap[LatchBlock]);
    for (SmallPtrSet<PHINode*,8>::iterator SI = Users.begin(), SE = Users.end();
         SI != SE; ++SI) {
      PHINode *PN = *SI;
      Value *InVal = PN->removeIncomingValue(LatchBlock, false);
      // If this value was defined in the loop, take the value defined by the
      // last iteration of the loop.
      if (Instruction *InValI = dyn_cast<Instruction>(InVal)) {
        if (L->contains(InValI->getParent()))
          InVal = LastValueMap[InVal];
      }
      PN->addIncoming(InVal, LastIterationBB);
    }
  }

  // Now, if we're doing complete unrolling, loop over the PHI nodes in the
  // original block, setting them to their incoming values.
  if (CompletelyUnroll) {
    BasicBlock *Preheader = L->getLoopPreheader();
    for (unsigned i = 0, e = OrigPHINode.size(); i != e; ++i) {
      PHINode *PN = OrigPHINode[i];
      PN->replaceAllUsesWith(PN->getIncomingValueForBlock(Preheader));
      Header->getInstList().erase(PN);
    }
  }

  // Now that all the basic blocks for the unrolled iterations are in place,
  // set up the branches to connect them.
  for (unsigned i = 0, e = Latches.size(); i != e; ++i) {
    // The original branch was replicated in each unrolled iteration.
    BranchInst *Term = cast<BranchInst>(Latches[i]->getTerminator());

    // The branch destination.
    unsigned j = (i + 1) % e;
    BasicBlock *Dest = Headers[j];
    bool NeedConditional = true;

    // For a complete unroll, make the last iteration end with a branch
    // to the exit block.
    if (CompletelyUnroll && j == 0) {
      Dest = LoopExit;
      NeedConditional = false;
    }

    // If we know the trip count or a multiple of it, we can safely use an
    // unconditional branch for some iterations.
    if (j != BreakoutTrip && (TripMultiple == 0 || j % TripMultiple != 0)) {
      NeedConditional = false;
    }

    if (NeedConditional) {
      // Update the conditional branch's successor for the following
      // iteration.
      Term->setSuccessor(!ContinueOnTrue, Dest);
    } else {
      Term->setUnconditionalDest(Dest);
      // Merge adjacent basic blocks, if possible.
      if (BasicBlock *Fold = FoldBlockIntoPredecessor(Dest, LI)) {
        std::replace(Latches.begin(), Latches.end(), Dest, Fold);
        std::replace(Headers.begin(), Headers.end(), Dest, Fold);
      }
    }
  }

  // At this point, the code is well formed.  We now do a quick sweep over the
  // inserted code, doing constant propagation and dead code elimination as we
  // go.
  const std::vector<BasicBlock*> &NewLoopBlocks = L->getBlocks();
  for (std::vector<BasicBlock*>::const_iterator BB = NewLoopBlocks.begin(),
       BBE = NewLoopBlocks.end(); BB != BBE; ++BB)
    for (BasicBlock::iterator I = (*BB)->begin(), E = (*BB)->end(); I != E; ) {
      Instruction *Inst = I++;

      if (isInstructionTriviallyDead(Inst))
        (*BB)->getInstList().erase(Inst);
      else if (Constant *C = ConstantFoldInstruction(Inst,
                                                     Header->getContext())) {
        Inst->replaceAllUsesWith(C);
        (*BB)->getInstList().erase(Inst);
      }
    }

  NumCompletelyUnrolled += CompletelyUnroll;
  ++NumUnrolled;
  // Remove the loop from the LoopPassManager if it's completely removed.
  if (CompletelyUnroll && LPM != NULL)
    LPM->deleteLoopFromQueue(L);

  // If we didn't completely unroll the loop, it should still be in LCSSA form.
  if (!CompletelyUnroll)
    assert(L->isLCSSAForm());

  return true;
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <libaddressinput/address_normalizer.h>

#include <libaddressinput/address_data.h>
#include <libaddressinput/address_field.h>
#include <libaddressinput/preload_supplier.h>

#include <cassert>
#include <cstddef>
#include <string>
#include <vector>

#include "lookup_key.h"
#include "rule.h"
#include "util/string_compare.h"

namespace i18n {
namespace addressinput {

AddressNormalizer::AddressNormalizer(const PreloadSupplier* supplier)
    : supplier_(supplier),
      compare_(new StringCompare) {
  assert(supplier_ != NULL);
}

AddressNormalizer::~AddressNormalizer() {}

void AddressNormalizer::Normalize(AddressData* address) const {
  assert(address != NULL);
  assert(supplier_->IsLoaded(address->region_code));

  AddressData region_address;
  region_address.region_code = address->region_code;
  LookupKey parent_key;
  parent_key.FromAddress(region_address);
  const Rule* parent_rule = supplier_->GetRule(parent_key);
  assert(parent_rule != NULL);

  std::vector<std::string> languages(parent_rule->GetLanguages());

  if (languages.empty()) {
    languages.push_back("");
  } else {
    languages[0] = "";  // The default language doesn't need a tag on the id.
  }

  LookupKey lookup_key;
  for (size_t depth = 1; depth < arraysize(LookupKey::kHierarchy); ++depth) {
    AddressField field = LookupKey::kHierarchy[depth];
    if (address->IsFieldEmpty(field)) {
      return;
    }
    const std::string& field_value = address->GetFieldValue(field);
    bool no_match_found_yet = true;

    const std::vector<std::string>& sub_keys = parent_rule->GetSubKeys();

    for (int i = 0; i < sub_keys.size(); i++) {
      const std::string& sub_key = sub_keys[i];
      if (!no_match_found_yet)
        break;
      for (const std::string& language : languages) {
        lookup_key.set_language(language);
        lookup_key.FromLookupKey(parent_key, sub_key);
        const Rule* rule = supplier_->GetRule(lookup_key);
        assert(rule != NULL);

        bool matches_latin_name =
            compare_->NaturalEquals(field_value, rule->GetLatinName());
        bool matches_local_name_id =
            compare_->NaturalEquals(field_value, sub_key) ||
            compare_->NaturalEquals(field_value, rule->GetName());
        if (matches_latin_name || matches_local_name_id) {
          address->SetFieldValue(
              field, matches_latin_name ? rule->GetLatinName() : sub_key);
          no_match_found_yet = false;
          parent_key.FromLookupKey(parent_key, sub_key);
          parent_rule = supplier_->GetRule(parent_key);
          assert(parent_rule != NULL);
          break;
        }
      }
    }
    if (no_match_found_yet) {
      return;  // Abort search.
    }
  }
}

}  // namespace addressinput
}  // namespace i18n
<commit_msg>(AUTOMATIC) opensource update (#134)<commit_after>// Copyright (C) 2014 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <libaddressinput/address_normalizer.h>

#include <libaddressinput/address_data.h>
#include <libaddressinput/address_field.h>
#include <libaddressinput/preload_supplier.h>

#include <cassert>
#include <cstddef>
#include <string>
#include <vector>

#include "lookup_key.h"
#include "rule.h"
#include "util/string_compare.h"

namespace i18n {
namespace addressinput {

AddressNormalizer::AddressNormalizer(const PreloadSupplier* supplier)
    : supplier_(supplier),
      compare_(new StringCompare) {
  assert(supplier_ != NULL);
}

AddressNormalizer::~AddressNormalizer() {}

void AddressNormalizer::Normalize(AddressData* address) const {
  assert(address != NULL);
  assert(supplier_->IsLoaded(address->region_code));

  AddressData region_address;
  region_address.region_code = address->region_code;
  LookupKey parent_key;
  parent_key.FromAddress(region_address);
  const Rule* parent_rule = supplier_->GetRule(parent_key);
  assert(parent_rule != NULL);

  std::vector<std::string> languages(parent_rule->GetLanguages());

  if (languages.empty()) {
    languages.push_back("");
  } else {
    languages[0] = "";  // The default language doesn't need a tag on the id.
  }

  LookupKey lookup_key;
  for (size_t depth = 1; depth < arraysize(LookupKey::kHierarchy); ++depth) {
    AddressField field = LookupKey::kHierarchy[depth];
    if (address->IsFieldEmpty(field)) {
      return;
    }
    const std::string& field_value = address->GetFieldValue(field);
    bool no_match_found_yet = true;

    const std::vector<std::string>& sub_keys = parent_rule->GetSubKeys();

    for (size_t i = 0; i < sub_keys.size(); i++) {
      const std::string& sub_key = sub_keys[i];
      if (!no_match_found_yet)
        break;
      for (const std::string& language : languages) {
        lookup_key.set_language(language);
        lookup_key.FromLookupKey(parent_key, sub_key);
        const Rule* rule = supplier_->GetRule(lookup_key);
        assert(rule != NULL);

        bool matches_latin_name =
            compare_->NaturalEquals(field_value, rule->GetLatinName());
        bool matches_local_name_id =
            compare_->NaturalEquals(field_value, sub_key) ||
            compare_->NaturalEquals(field_value, rule->GetName());
        if (matches_latin_name || matches_local_name_id) {
          address->SetFieldValue(
              field, matches_latin_name ? rule->GetLatinName() : sub_key);
          no_match_found_yet = false;
          parent_key.FromLookupKey(parent_key, sub_key);
          parent_rule = supplier_->GetRule(parent_key);
          assert(parent_rule != NULL);
          break;
        }
      }
    }
    if (no_match_found_yet) {
      return;  // Abort search.
    }
  }
}

}  // namespace addressinput
}  // namespace i18n
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "cql3/keyspace_element_name.hh"

namespace cql3 {

void keyspace_element_name::set_keyspace(std::string_view ks, bool keep_case)
{
    _ks_name = to_internal_name(ks, keep_case);
}

bool keyspace_element_name::has_keyspace() const
{
    return bool(_ks_name);
}

const sstring& keyspace_element_name::get_keyspace() const
{
    return *_ks_name;
}

sstring keyspace_element_name::to_internal_name(std::string_view view, bool keep_case)
{
    sstring name(view);
    if (!keep_case) {
        std::transform(name.begin(), name.end(), name.begin(), ::tolower);
    }
    return name;
}

sstring keyspace_element_name::to_string() const
{
    return has_keyspace() ? (get_keyspace() + ".") : "";
}

}
<commit_msg>cql3: assert that unengaged optional is not accessed in keyspace_element_name::get_keyspace()<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright (C) 2015 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "cql3/keyspace_element_name.hh"

namespace cql3 {

void keyspace_element_name::set_keyspace(std::string_view ks, bool keep_case)
{
    _ks_name = to_internal_name(ks, keep_case);
}

bool keyspace_element_name::has_keyspace() const
{
    return bool(_ks_name);
}

const sstring& keyspace_element_name::get_keyspace() const
{
    assert(_ks_name);
    return *_ks_name;
}

sstring keyspace_element_name::to_internal_name(std::string_view view, bool keep_case)
{
    sstring name(view);
    if (!keep_case) {
        std::transform(name.begin(), name.end(), name.begin(), ::tolower);
    }
    return name;
}

sstring keyspace_element_name::to_string() const
{
    return has_keyspace() ? (get_keyspace() + ".") : "";
}

}
<|endoftext|>


<commit_before>//美团校招2015 哈尔滨(2)
//有一组随机排列的字母数组，请编写一个时间复杂度为O(n)的算法，使得这些字母从小到大顺序排好。
//说明：字母区分大小写，相同的字母，排序后小写排在大写前。
//例如：R,B,B,b,W,W,B,R,B,w
//排序后：b,B,B,B,B,R,R,w,W,W
//1)描写思路（2分）
//2）请用你熟悉的编程语言编写代码实现（8分）
#include <iostream>
#include <cstring>
using namespace std;

string countsort(string &s)
{
  const int SIZE = 26;
  const int GAP = 32;
  int count[SIZE];
  memset(count, 0, sizeof(count));
  for (auto c : s) {
    int index = c - 'A';
    // when c is lowerletter count its number to the upper too
    if (index > SIZE)
      index -= GAP;
    count[index]++;
  }
  for (int i = 1; i < SIZE; i++) {
    count[i] += count[i - 1];
  }

  string result;
  result.reserve(s.size());

  for (auto riter = s.rbegin(); riter != s.rend(); ++riter) {
    int index = *riter - 'A';
    // when c is lowerletter, put it to the (index - 1)'s count pos..
    // great!!
    if (index > SIZE) {
      index -= GAP;
      result[count[index - 1]] = *riter;
      continue;
    }
    result[count[index] - 1] = *riter;
    count[index]--;
  }

  return result;
}

int main()
{
  string s("RBBbWWBRBw");
  cout << s << endl;
  string result = countsort(s);

  cout << result.data() << endl;

  return 0;
}
<commit_msg>Update countsort.cc<commit_after>//美团校招2015 哈尔滨(2)
//有一组随机排列的字母数组，请编写一个时间复杂度为O(n)的算法，使得这些字母从小到大顺序排好。
//说明：字母区分大小写，相同的字母，排序后小写排在大写前。
//例如：R,B,B,b,W,W,B,R,B,w
//排序后：b,B,B,B,B,R,R,w,W,W
//1)描写思路（2分）
//2）请用你熟悉的编程语言编写代码实现（8分）
#include <iostream>
#include <cstring>
using namespace std;

string countsort(string &s)
{
  const int SIZE = 26;
  const int GAP = 32;
  int count[SIZE];
  memset(count, 0, sizeof(count));
  for (auto c : s) {
    int index = c - 'A';
    // when c is lowerletter count its number to the upper too
    if (index > SIZE)
      index -= GAP;
    count[index]++;
  }
  for (int i = 1; i < SIZE; i++) {
    count[i] += count[i - 1];
  }

  string result;
  result.reserve(s.size());

  for (auto riter = s.rbegin(); riter != s.rend(); ++riter) {
    int index = *riter - 'A';
    // when c is lowerletter, put it to the (index - 1)'s count pos..
    // great!!
    if (index > SIZE) {
      index -= GAP;
      result[count[index - 1]] = *riter;
      // decrease the corresponding count
      count[index]--;
      continue;
    }
    result[count[index] - 1] = *riter;
    count[index]--;
  }

  return result;
}

int main()
{
  string s("RBBbWWBRBw");
  cout << s << endl;
  string result = countsort(s);

  cout << result.data() << endl;

  return 0;
}
<|endoftext|>


<commit_before>#include "HexView.h"
#include "Log.h"
#include <stdio.h>
#include <assert.h>

HexView::HexView(const char* filename, Window* parent) : Window(parent)
{
    m_fp = 0;
    m_buffer = 0;
    m_topLine = 0;
    m_selected = 0;
    fopen_s(&m_fp, filename, "rb");
    if (m_fp)
    {
        fseek(m_fp, 0, SEEK_END);
        m_fileSize = ftell(m_fp);
        fseek(m_fp, 0, SEEK_SET);
    }
}

HexView::~HexView()
{
    if (m_fp)
        fclose(m_fp);
}

void HexView::OnWindowRefreshed()
{
    Window::OnWindowRefreshed();

    s_consoleBuffer->FillRect(0, 1, m_width, m_height, ' ', FOREGROUND_RED);
    s_consoleBuffer->FillLine(m_height + 1, ' ', BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
    s_consoleBuffer->Write(2, m_height + 1, BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED, "%08X / %08X", m_selected, m_fileSize - 1);

    if (!m_fp)
        return;

    assert(m_buffer);
    int offset = m_topLine << 4;
    int selectedLine = GetSelectedLine();
    bool done = false;

    for (int j = 0; j < m_height; j++)
    {
        int y = 1 + j;
        int x = 2;
        WORD colour = 0;

        int curr = (m_selected >> 4) * (m_height - 1) / (m_fileSize >> 4);
        char c = j == curr ? 178 : 176;
        s_consoleBuffer->Write(0, y, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, "%c", c);

        if (done)
            continue;

        if ((offset >> 4) == selectedLine)
        {
            // Highlight the selected line's offset text.
            colour = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
        }
        else
        {
            colour = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
        }

        s_consoleBuffer->Write(x, y, colour, "%08X", offset);
        x += 9;

        for (int i = 0; i < 16; i++, offset++)
        {
            int bufferIndex = offset - (m_topLine << 4);
            if (offset >= m_fileSize)
            {
                done = true;
                break;
            }

            assert(bufferIndex >= 0 && bufferIndex < m_fileSize);
            unsigned char c = m_buffer[bufferIndex];

            if (offset == m_selected)
            {
                // Highlight the selected byte.
                colour = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
            }
            else
            {
                colour = FOREGROUND_GREEN;
            }

            int xx = x + (i * 3);
            s_consoleBuffer->Write(xx, y, colour, "%02X", c);

            xx = x + (16 * 3) + i;
            if (c < ' ')
                c = '.';

            if (offset == m_selected)
            {
                // Highlight the selected character.
                colour = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
            }
            else
            {
                colour = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
            }
            s_consoleBuffer->Write(xx, y, colour, "%c", c);
        }
    }
}

void HexView::OnWindowResized(int width, int height)
{
    // Our height is actually smaller.
    height -= 2;
    Window::OnWindowResized(width, height);
    CacheFile(true);
}

void HexView::CacheFile(bool resizeBuffer)
{
    if (!m_fp)
        return;

    assert(m_topLine >= 0);
    int offset = m_topLine << 4;
    assert(offset >= 0 && offset < m_fileSize);

    if (resizeBuffer)
    {
        assert(m_height >= 0);
        int screenSize = m_height << 4;

        delete[] m_buffer;
        m_bufferSize = offset + screenSize >= m_fileSize ? m_fileSize - offset : screenSize;
        m_buffer = new unsigned char[m_bufferSize];
        memset(m_buffer, 0, m_bufferSize);
    }

    fseek(m_fp, offset, SEEK_SET);
    fread_s(m_buffer, m_bufferSize, 1, m_bufferSize, m_fp);
}

void HexView::OnKeyEvent(KeyEvent& keyEvent)
{
    Window::OnKeyEvent(keyEvent);

    if (!keyEvent.IsKeyDown())
        return;

    bool refresh = true;
    bool fullDraw = false;

    switch (keyEvent.GetVKKeyCode())
    {
        case VK_LEFT:
        {
            m_selected = max(m_selected - 1, 0);
            int selectedLine = GetSelectedLine();
            if (selectedLine < m_topLine)
            {
                m_topLine--;
                assert(m_topLine >= 0);
                fullDraw = true;
                CacheFile();
            }
            break;
        }

        case VK_RIGHT:
        {
            m_selected = min(m_selected + 1, m_fileSize - 1);
            int selectedLine = GetSelectedLine();
            int bottomLine = GetBottomLine();
            if (selectedLine > bottomLine)
            {
                m_topLine++;
                assert((m_topLine << 4) < m_fileSize);
                fullDraw = true;
                CacheFile();
            }
            break;
        }

        case VK_UP:
        {
            refresh = false;
            int selectedLine = GetSelectedLine();
            if (selectedLine == 0)
                break;

            refresh = true;
            m_selected = max(m_selected - 16, 0);
            selectedLine = GetSelectedLine();
            if (selectedLine < m_topLine)
            {
                m_topLine--;
                assert(m_topLine >= 0);
                fullDraw = true;
                CacheFile();
            }
            break;
        }

        case VK_DOWN:
        {
            refresh = false;
            int selectedLine = GetSelectedLine();
            int lastLine = GetLastLine();

            // If on the last line, don't move anywhere.
            if (selectedLine == lastLine)
                break;

            refresh = true;
            m_selected = min(m_selected + 16, m_fileSize - 1);
            selectedLine = GetSelectedLine();

            int bottomLine = GetBottomLine();
            if (selectedLine > bottomLine)
            {
                m_topLine++;
                assert((m_topLine << 4) < m_fileSize);
                fullDraw = true;
                CacheFile();
            }
            break;
        }

        case VK_HOME:
        {
            if (keyEvent.IsControlKeyDown(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
            {
                m_selected = 0;
                m_topLine = 0;
                fullDraw = true;
                CacheFile();
            }
            else
            {
                m_selected &= ~15;
            }
            break;
        }

        case VK_END:
        {
            if (keyEvent.IsControlKeyDown(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
            {
                m_selected = m_fileSize - 1;
                int selectedLine = GetSelectedLine();
                m_topLine = max(selectedLine - m_height + 1, 0);
                fullDraw = true;
                CacheFile();
            }
            else
            {
                m_selected = min(m_selected | 15, m_fileSize - 1);
            }
            break;
        }

        // Page down.
        case VK_NEXT:
        {
            // Current selection column in the last line.
            int lastLineSelected = min(((m_fileSize - 1) & ~0xf) | (m_selected & 0xf), m_fileSize - 1);

            if (keyEvent.IsControlKeyDown(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
            {
                // Control is down. Go to the bottom of the current page.
                int bottomLine = GetBottomLine();

                // Select the offset at the bottom of the current page.
                m_selected = min((bottomLine << 4) | (m_selected & 0xf), lastLineSelected);
            }
            else
            {
                int selectedLine = GetSelectedLine();

                // Get the current distance from the selection to the top line.
                int delta = selectedLine - m_topLine;

                // Select the offset at one page down from the current.
                m_selected = min(m_selected + (m_height << 4), lastLineSelected);

                // Determine if we need to update the top line.
                selectedLine = GetSelectedLine();
                int bottomLine = GetBottomLine();
                if (selectedLine > bottomLine)
                {
                    // Update the top line, but maintain the current selection distance so the cursor
                    // never moves.
                    m_topLine = max(selectedLine - delta, 0);
                    fullDraw = true;
                    CacheFile();
                }
            }
            break;
        }

        // Page up.
        case VK_PRIOR:
        {
            if (keyEvent.IsControlKeyDown(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
            {
                // Control is down. Go to the top of the current page.
                // Select the offset at the top of the current page.
                m_selected = (m_topLine << 4) | m_selected & 0xf;
            }
            else
            {
                int selectedLine = GetSelectedLine();

                // Get the current distance from the selection to the top line.
                int delta = selectedLine - m_topLine;

                // Select the offset at one page up from the current.
                m_selected = max(m_selected - (m_height << 4), (m_selected & 0xf));

                // Determine if we need to update the top line.
                selectedLine = GetSelectedLine();
                if (selectedLine < m_topLine)
                {
                    // Update the top line, but maintain the current selection distance so the cursor
                    // never moves.
                    m_topLine = max(selectedLine - delta, 0);
                    fullDraw = true;
                    CacheFile();
                }
            }
            break;
        }

        case VK_F5:
        {
            fullDraw = true;
            break;
        }
    }

    if (refresh)
        Window::Refresh(fullDraw);
}
<commit_msg>Handle files of 0 size or files that failed to load.<commit_after>#include "HexView.h"
#include "Log.h"
#include <stdio.h>
#include <assert.h>

HexView::HexView(const char* filename, Window* parent) : Window(parent)
{
    m_fp = 0;
    m_buffer = 0;
    m_topLine = 0;
    m_selected = 0;
    m_fileSize = 0;
    fopen_s(&m_fp, filename, "rb");
    if (m_fp)
    {
        fseek(m_fp, 0, SEEK_END);
        m_fileSize = ftell(m_fp);
        fseek(m_fp, 0, SEEK_SET);
    }
}

HexView::~HexView()
{
    if (m_fp)
        fclose(m_fp);
}

void HexView::OnWindowRefreshed()
{
    Window::OnWindowRefreshed();

    s_consoleBuffer->FillRect(0, 1, m_width, m_height, ' ', FOREGROUND_RED);
    s_consoleBuffer->FillLine(m_height + 1, ' ', BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
    s_consoleBuffer->Write(2, m_height + 1, BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED, "%08X / %08X", m_selected, max(m_fileSize - 1, 0));

    if (!m_fp)
        return;

    assert(m_buffer);
    int offset = m_topLine << 4;
    int selectedLine = GetSelectedLine();
    bool done = false;

    for (int j = 0; j < m_height; j++)
    {
        int y = 1 + j;
        int x = 2;
        WORD colour = 0;

        int curr = (m_selected >> 4) * (m_height - 1) / (m_fileSize >> 4);
        char c = j == curr ? 178 : 176;
        s_consoleBuffer->Write(0, y, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, "%c", c);

        if (done)
            continue;

        if ((offset >> 4) == selectedLine)
        {
            // Highlight the selected line's offset text.
            colour = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
        }
        else
        {
            colour = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
        }

        s_consoleBuffer->Write(x, y, colour, "%08X", offset);
        x += 9;

        for (int i = 0; i < 16; i++, offset++)
        {
            int bufferIndex = offset - (m_topLine << 4);
            if (offset >= m_fileSize)
            {
                done = true;
                break;
            }

            assert(bufferIndex >= 0 && bufferIndex < m_fileSize);
            unsigned char c = m_buffer[bufferIndex];

            if (offset == m_selected)
            {
                // Highlight the selected byte.
                colour = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
            }
            else
            {
                colour = FOREGROUND_GREEN;
            }

            int xx = x + (i * 3);
            s_consoleBuffer->Write(xx, y, colour, "%02X", c);

            xx = x + (16 * 3) + i;
            if (c < ' ')
                c = '.';

            if (offset == m_selected)
            {
                // Highlight the selected character.
                colour = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
            }
            else
            {
                colour = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
            }
            s_consoleBuffer->Write(xx, y, colour, "%c", c);
        }
    }
}

void HexView::OnWindowResized(int width, int height)
{
    // Our height is actually smaller.
    height -= 2;
    Window::OnWindowResized(width, height);
    CacheFile(true);
}

void HexView::CacheFile(bool resizeBuffer)
{
    if (!m_fp)
        return;

    assert(m_topLine >= 0);
    int offset = m_topLine << 4;
    assert(offset >= 0 && offset < m_fileSize);

    if (resizeBuffer)
    {
        assert(m_height >= 0);
        int screenSize = m_height << 4;

        delete[] m_buffer;
        m_bufferSize = offset + screenSize >= m_fileSize ? m_fileSize - offset : screenSize;
        m_buffer = new unsigned char[m_bufferSize];
        memset(m_buffer, 0, m_bufferSize);
    }

    fseek(m_fp, offset, SEEK_SET);
    fread_s(m_buffer, m_bufferSize, 1, m_bufferSize, m_fp);
}

void HexView::OnKeyEvent(KeyEvent& keyEvent)
{
    Window::OnKeyEvent(keyEvent);

    if (!keyEvent.IsKeyDown())
        return;

    bool refresh = true;
    bool fullDraw = false;

    switch (keyEvent.GetVKKeyCode())
    {
        case VK_LEFT:
        {
            m_selected = max(m_selected - 1, 0);
            int selectedLine = GetSelectedLine();
            if (selectedLine < m_topLine)
            {
                m_topLine--;
                assert(m_topLine >= 0);
                fullDraw = true;
                CacheFile();
            }
            break;
        }

        case VK_RIGHT:
        {
            m_selected = max(min(m_selected + 1, m_fileSize - 1), 0);
            int selectedLine = GetSelectedLine();
            int bottomLine = GetBottomLine();
            if (selectedLine > bottomLine)
            {
                m_topLine++;
                assert((m_topLine << 4) < m_fileSize);
                fullDraw = true;
                CacheFile();
            }
            break;
        }

        case VK_UP:
        {
            refresh = false;
            int selectedLine = GetSelectedLine();
            if (selectedLine == 0)
                break;

            refresh = true;
            m_selected = max(m_selected - 16, 0);
            selectedLine = GetSelectedLine();
            if (selectedLine < m_topLine)
            {
                m_topLine--;
                assert(m_topLine >= 0);
                fullDraw = true;
                CacheFile();
            }
            break;
        }

        case VK_DOWN:
        {
            refresh = false;
            int selectedLine = GetSelectedLine();
            int lastLine = GetLastLine();

            // If on the last line, don't move anywhere.
            if (selectedLine == lastLine)
                break;

            refresh = true;
            m_selected = max(min(m_selected + 16, m_fileSize - 1), 0);
            selectedLine = GetSelectedLine();

            int bottomLine = GetBottomLine();
            if (selectedLine > bottomLine)
            {
                m_topLine++;
                assert((m_topLine << 4) < m_fileSize);
                fullDraw = true;
                CacheFile();
            }
            break;
        }

        case VK_HOME:
        {
            if (keyEvent.IsControlKeyDown(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
            {
                m_selected = 0;
                m_topLine = 0;
                fullDraw = true;
                CacheFile();
            }
            else
            {
                m_selected &= ~15;
            }
            break;
        }

        case VK_END:
        {
            if (keyEvent.IsControlKeyDown(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
            {
                m_selected = max(m_fileSize - 1, 0);
                int selectedLine = GetSelectedLine();
                m_topLine = max(selectedLine - m_height + 1, 0);
                fullDraw = true;
                CacheFile();
            }
            else
            {
                m_selected = max(min(m_selected | 15, m_fileSize - 1), 0);
            }
            break;
        }

        // Page down.
        case VK_NEXT:
        {
            // Current selection column in the last line.
            int lastLineSelected = max(min(((m_fileSize - 1) & ~0xf) | (m_selected & 0xf), m_fileSize - 1), 0);

            if (keyEvent.IsControlKeyDown(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
            {
                // Control is down. Go to the bottom of the current page.
                int bottomLine = GetBottomLine();

                // Select the offset at the bottom of the current page.
                m_selected = min((bottomLine << 4) | (m_selected & 0xf), lastLineSelected);
            }
            else
            {
                int selectedLine = GetSelectedLine();

                // Get the current distance from the selection to the top line.
                int delta = selectedLine - m_topLine;

                // Select the offset at one page down from the current.
                m_selected = min(m_selected + (m_height << 4), lastLineSelected);

                // Determine if we need to update the top line.
                selectedLine = GetSelectedLine();
                int bottomLine = GetBottomLine();
                if (selectedLine > bottomLine)
                {
                    // Update the top line, but maintain the current selection distance so the cursor
                    // never moves.
                    m_topLine = max(selectedLine - delta, 0);
                    fullDraw = true;
                    CacheFile();
                }
            }
            break;
        }

        // Page up.
        case VK_PRIOR:
        {
            if (keyEvent.IsControlKeyDown(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
            {
                // Control is down. Go to the top of the current page.
                // Select the offset at the top of the current page.
                m_selected = (m_topLine << 4) | m_selected & 0xf;
            }
            else
            {
                int selectedLine = GetSelectedLine();

                // Get the current distance from the selection to the top line.
                int delta = selectedLine - m_topLine;

                // Select the offset at one page up from the current.
                m_selected = max(m_selected - (m_height << 4), (m_selected & 0xf));

                // Determine if we need to update the top line.
                selectedLine = GetSelectedLine();
                if (selectedLine < m_topLine)
                {
                    // Update the top line, but maintain the current selection distance so the cursor
                    // never moves.
                    m_topLine = max(selectedLine - delta, 0);
                    fullDraw = true;
                    CacheFile();
                }
            }
            break;
        }

        case VK_F5:
        {
            fullDraw = true;
            break;
        }
    }

    if (refresh)
        Window::Refresh(fullDraw);
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*-
 *
 * Quadra, an action puzzle game
 * Copyright (C) 1998-2000  Ludus Design
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "cfgfile.h"

#include <string.h>
#include <stdio.h>
#include "input.h"
#include "res.h"
#include "global.h"
#include "crypt.h"
#include "video.h"
#include "version.h"
#include "unicode.h"

RCSID("$Id$")

const int Config::game_version = 19;
int Config::net_version = 24;

const int Config::major = VERSION_MAJOR;
const int Config::minor = VERSION_MINOR;
const int Config::patchlevel = VERSION_PATCHLEVEL;

/* FIXME: we should remove all occurence of Config::xtreme */
bool Config::xtreme = false;
char Config::user_name[64] = {""};

Config::Config() {
	fname[0]=0;
}

Config::~Config() {
}

void Config::default_config() {
	memset(&version, 0, sizeof(version));
	memset(&info, 0, sizeof(info));
	memset(player, 0, sizeof(player));
	memset(player2, 0, sizeof(player2));
	memset(&info2, 0, sizeof(info2));
	memset(&info3, 0, sizeof(info3));
	info.language = 0;
	info.setup_player = 0;
	info.cdmusic = 0; // 0=no music  1=auto-change  2=loop all
	info.multi_level = 1;
	info.unlock_theme = 0;
	info.port_number = 3456;
	info.mouse_speed = 100;
	info.pane[0] = 2;
	info.pane[1] = 0;
	info.pane[2] = 3;
	info.update_rate = 10;
	memset(info.book, sizeof(info.book), 0);
	info.game_name[0] = 0;
	info.game_type = info.level_up = info.level_start = info.combo_min = info.game_end = 0;
	info.game_public = 1;
	info.game_end_value = 1;

	for(int i=0; i<3; i++) {
		sprintf(st,"#%i", i+1);
		strcpy(player[i].name, st);
		player[i].color = i;
		player[i].shadow = 0;
		player[i].smooth = 1;
		player[i].repeat = -1;
		player2[i].h_repeat = 2;
		player2[i].v_repeat = 2;
		player2[i].continuous = 1;
		player[i].key[0] = KEY_LEFTARROW;
		player[i].key[1] = KEY_RIGHTARROW;
		player[i].key[2] = KEY_UPARROW;
		player[i].key[3] = KEY_DOWNARROW;
		player[i].key[4] = KEY_UPARROW;
		player2[i].key[0] = KEY_RSHIFT;
		player2[i].key[1] = KEY_SPACE;
	}
}

void Config::read() {
	if(!fname[0])
		snprintf(fname, sizeof(fname) - 1, "%s/%s", quadradir, "quadra.cfg");

	int i;

	Res_dos res(fname, RES_TRY);
	memset(&version, 0, sizeof(version));
	memset(&info, 0, sizeof(info));
	memset(player, 0, sizeof(player));
	memset(player2, 0, sizeof(player2));
	memset(&info2, 0, sizeof(info2));
	memset(&info3, 0, sizeof(info3));
	warning = 0;
	if(!res.exist) {
		default_config();
		warning = 1;
	} else {
		if(res.size() != (sizeof(version) + sizeof(info) + sizeof(player)) &&
		   res.size() != (sizeof(version) + sizeof(info) + sizeof(player) + sizeof(player2) + sizeof(info2)) &&
       res.size() != (sizeof(version) + sizeof(info) + sizeof(player) + sizeof(player2) + sizeof(info2) + sizeof(info3))) {
			default_config();
			warning = 2;
		} else {
			version = -1;
			res.read(&version, sizeof(version));
			if(version != game_version) {
				default_config();
				warning = 2;
			} else {
				res.read(&info, sizeof(info));
				res.read(player, sizeof(player));
				//Those may not be present, but the default is all-zero anyway
				res.read(player2, sizeof(player2));
				res.read(&info2, sizeof(info2));
				res.read(&info3, sizeof(info3));
			}
		}
	}

	if(info3.latest_version[0] == 0)
	{
		strcpy(info3.latest_version, VERSION_STRING);
	}

	for(i=0; i<3; i++) {
		player[i].name[39] = 0;
		if(player[i].color<0 || player[i].color>=MAXTEAMS)
			player[i].color=i;
		if(player[i].shadow<0 || player[i].shadow>1)
			player[i].shadow=1;
		if(player[i].smooth<0 || player[i].smooth>1)
			player[i].smooth=1;
		if(player[i].repeat<-1 || player[i].repeat>3)
			player2[i].h_repeat=player2[i].v_repeat=2;
		else
			if(player[i].repeat>=0) {
				player2[i].h_repeat=player[i].repeat;
				player2[i].v_repeat=player[i].repeat;
			}
		if(player2[i].h_repeat<0 || player2[i].h_repeat>3) {
			player2[i].h_repeat=2;
		}
		if(player2[i].v_repeat<0 || player2[i].v_repeat>3) {
			player2[i].v_repeat=2;
		}
		player[i].repeat = -1;
		if(player2[i].continuous<0 || player2[i].continuous>1)
			player2[i].continuous=1;
		if(player2[i].handicap<0 || player2[i].handicap>4)
			player2[i].handicap=0;
		player2[i].ngPasswd[63]=0;
		player2[i].ngTeam[39]=0;
		player2[i].ngTeamPasswd[63]=0;
	}
	for(i=0; i<10; i++) {
		info.book[i][255] = 0;
	}
	info2.proxy_address[127] = 0;
	info3.last_modified[63] = 0;
	info3.default_game_server_address[255] = 0;
	info3.latest_version[255] = 0;
}

void fix_str(char *st, Dword len) {
	bool in_str(true);

	for(Dword i = 0; i < len; ++i)
		if(!in_str)
			st[i] = 0;
		else
			if(!st[i])
				in_str = false;
	st[len - 1] = 0;
}

void Config::write() {
	int i;
	if(!fname[0])
		snprintf(fname, sizeof(fname) - 1, "%s/%s", quadradir, "quadra.cfg");

	if(!video_is_dumb) {
		Res_dos res(fname, RES_CREATE);
		if(res.exist) {
			version = game_version;
			res.write(&version, sizeof(version));
			for(i=0; i<10; i++)
				fix_str(info.book[i], 256);
			fix_str(info.game_name, 32);
			fix_str(info.game_server_address, 256);
			res.write(&info, sizeof(info));
			for(i=0; i<3; i++) {
				fix_str(player[i].name, 40);
				fix_str(player2[i].ngPasswd, 64);
				fix_str(player2[i].ngTeam, 40);
				fix_str(player2[i].ngTeamPasswd, 64);
			}
			res.write(player, sizeof(player));
			res.write(player2, sizeof(player2));
			fix_str(info2.proxy_address, 128);
			res.write(&info2, sizeof(info2));
			fix_str(info3.last_modified, 64);
			fix_str(info3.default_game_server_address, 256);
			fix_str(info3.latest_version, 256);
			res.write(&info3, sizeof(info3));
		}
	}
}

void Config::get_player_hash(Byte* buf, unsigned qplayer) {
	if(player2[qplayer].ngPasswd[0]) {
		Unicode uni_p(player[qplayer].name);
		uni_p.cat(player2[qplayer].ngPasswd);
		Crypt name_crypt;
		name_crypt.step(uni_p, uni_p.size());
		name_crypt.finalize(false);
		memcpy(buf, name_crypt.get_digest(), 16);
	}
	else
		memset(buf, 0, 16);
}

void Config::get_team_hash(Byte* buf, unsigned qplayer) {
	if(player2[qplayer].ngTeam[0] && player2[qplayer].ngTeamPasswd[0]) {
		Unicode uni_t(player2[qplayer].ngTeam);
		uni_t.cat(player2[qplayer].ngTeamPasswd);
		Crypt team_crypt;
		team_crypt.step(uni_t, uni_t.size());
		memcpy(buf, team_crypt.get_digest(), 16);
	}
	else
		memset(buf, 0, 16);
}

Config config;
<commit_msg>This memset had two inverted parameters since, well, forever.<commit_after>/* -*- Mode: C++; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*-
 *
 * Quadra, an action puzzle game
 * Copyright (C) 1998-2000  Ludus Design
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "cfgfile.h"

#include <string.h>
#include <stdio.h>
#include "input.h"
#include "res.h"
#include "global.h"
#include "crypt.h"
#include "video.h"
#include "version.h"
#include "unicode.h"

RCSID("$Id$")

const int Config::game_version = 19;
int Config::net_version = 24;

const int Config::major = VERSION_MAJOR;
const int Config::minor = VERSION_MINOR;
const int Config::patchlevel = VERSION_PATCHLEVEL;

/* FIXME: we should remove all occurence of Config::xtreme */
bool Config::xtreme = false;
char Config::user_name[64] = {""};

Config::Config() {
	fname[0]=0;
}

Config::~Config() {
}

void Config::default_config() {
	memset(&version, 0, sizeof(version));
	memset(&info, 0, sizeof(info));
	memset(player, 0, sizeof(player));
	memset(player2, 0, sizeof(player2));
	memset(&info2, 0, sizeof(info2));
	memset(&info3, 0, sizeof(info3));
	info.language = 0;
	info.setup_player = 0;
	info.cdmusic = 0; // 0=no music  1=auto-change  2=loop all
	info.multi_level = 1;
	info.unlock_theme = 0;
	info.port_number = 3456;
	info.mouse_speed = 100;
	info.pane[0] = 2;
	info.pane[1] = 0;
	info.pane[2] = 3;
	info.update_rate = 10;
	memset(info.book, 0, sizeof(info.book));
	info.game_name[0] = 0;
	info.game_type = info.level_up = info.level_start = info.combo_min = info.game_end = 0;
	info.game_public = 1;
	info.game_end_value = 1;

	for(int i=0; i<3; i++) {
		sprintf(st,"#%i", i+1);
		strcpy(player[i].name, st);
		player[i].color = i;
		player[i].shadow = 0;
		player[i].smooth = 1;
		player[i].repeat = -1;
		player2[i].h_repeat = 2;
		player2[i].v_repeat = 2;
		player2[i].continuous = 1;
		player[i].key[0] = KEY_LEFTARROW;
		player[i].key[1] = KEY_RIGHTARROW;
		player[i].key[2] = KEY_UPARROW;
		player[i].key[3] = KEY_DOWNARROW;
		player[i].key[4] = KEY_UPARROW;
		player2[i].key[0] = KEY_RSHIFT;
		player2[i].key[1] = KEY_SPACE;
	}
}

void Config::read() {
	if(!fname[0])
		snprintf(fname, sizeof(fname) - 1, "%s/%s", quadradir, "quadra.cfg");

	int i;

	Res_dos res(fname, RES_TRY);
	memset(&version, 0, sizeof(version));
	memset(&info, 0, sizeof(info));
	memset(player, 0, sizeof(player));
	memset(player2, 0, sizeof(player2));
	memset(&info2, 0, sizeof(info2));
	memset(&info3, 0, sizeof(info3));
	warning = 0;
	if(!res.exist) {
		default_config();
		warning = 1;
	} else {
		if(res.size() != (sizeof(version) + sizeof(info) + sizeof(player)) &&
		   res.size() != (sizeof(version) + sizeof(info) + sizeof(player) + sizeof(player2) + sizeof(info2)) &&
       res.size() != (sizeof(version) + sizeof(info) + sizeof(player) + sizeof(player2) + sizeof(info2) + sizeof(info3))) {
			default_config();
			warning = 2;
		} else {
			version = -1;
			res.read(&version, sizeof(version));
			if(version != game_version) {
				default_config();
				warning = 2;
			} else {
				res.read(&info, sizeof(info));
				res.read(player, sizeof(player));
				//Those may not be present, but the default is all-zero anyway
				res.read(player2, sizeof(player2));
				res.read(&info2, sizeof(info2));
				res.read(&info3, sizeof(info3));
			}
		}
	}

	if(info3.latest_version[0] == 0)
	{
		strcpy(info3.latest_version, VERSION_STRING);
	}

	for(i=0; i<3; i++) {
		player[i].name[39] = 0;
		if(player[i].color<0 || player[i].color>=MAXTEAMS)
			player[i].color=i;
		if(player[i].shadow<0 || player[i].shadow>1)
			player[i].shadow=1;
		if(player[i].smooth<0 || player[i].smooth>1)
			player[i].smooth=1;
		if(player[i].repeat<-1 || player[i].repeat>3)
			player2[i].h_repeat=player2[i].v_repeat=2;
		else
			if(player[i].repeat>=0) {
				player2[i].h_repeat=player[i].repeat;
				player2[i].v_repeat=player[i].repeat;
			}
		if(player2[i].h_repeat<0 || player2[i].h_repeat>3) {
			player2[i].h_repeat=2;
		}
		if(player2[i].v_repeat<0 || player2[i].v_repeat>3) {
			player2[i].v_repeat=2;
		}
		player[i].repeat = -1;
		if(player2[i].continuous<0 || player2[i].continuous>1)
			player2[i].continuous=1;
		if(player2[i].handicap<0 || player2[i].handicap>4)
			player2[i].handicap=0;
		player2[i].ngPasswd[63]=0;
		player2[i].ngTeam[39]=0;
		player2[i].ngTeamPasswd[63]=0;
	}
	for(i=0; i<10; i++) {
		info.book[i][255] = 0;
	}
	info2.proxy_address[127] = 0;
	info3.last_modified[63] = 0;
	info3.default_game_server_address[255] = 0;
	info3.latest_version[255] = 0;
}

void fix_str(char *st, Dword len) {
	bool in_str(true);

	for(Dword i = 0; i < len; ++i)
		if(!in_str)
			st[i] = 0;
		else
			if(!st[i])
				in_str = false;
	st[len - 1] = 0;
}

void Config::write() {
	int i;
	if(!fname[0])
		snprintf(fname, sizeof(fname) - 1, "%s/%s", quadradir, "quadra.cfg");

	if(!video_is_dumb) {
		Res_dos res(fname, RES_CREATE);
		if(res.exist) {
			version = game_version;
			res.write(&version, sizeof(version));
			for(i=0; i<10; i++)
				fix_str(info.book[i], 256);
			fix_str(info.game_name, 32);
			fix_str(info.game_server_address, 256);
			res.write(&info, sizeof(info));
			for(i=0; i<3; i++) {
				fix_str(player[i].name, 40);
				fix_str(player2[i].ngPasswd, 64);
				fix_str(player2[i].ngTeam, 40);
				fix_str(player2[i].ngTeamPasswd, 64);
			}
			res.write(player, sizeof(player));
			res.write(player2, sizeof(player2));
			fix_str(info2.proxy_address, 128);
			res.write(&info2, sizeof(info2));
			fix_str(info3.last_modified, 64);
			fix_str(info3.default_game_server_address, 256);
			fix_str(info3.latest_version, 256);
			res.write(&info3, sizeof(info3));
		}
	}
}

void Config::get_player_hash(Byte* buf, unsigned qplayer) {
	if(player2[qplayer].ngPasswd[0]) {
		Unicode uni_p(player[qplayer].name);
		uni_p.cat(player2[qplayer].ngPasswd);
		Crypt name_crypt;
		name_crypt.step(uni_p, uni_p.size());
		name_crypt.finalize(false);
		memcpy(buf, name_crypt.get_digest(), 16);
	}
	else
		memset(buf, 0, 16);
}

void Config::get_team_hash(Byte* buf, unsigned qplayer) {
	if(player2[qplayer].ngTeam[0] && player2[qplayer].ngTeamPasswd[0]) {
		Unicode uni_t(player2[qplayer].ngTeam);
		uni_t.cat(player2[qplayer].ngTeamPasswd);
		Crypt team_crypt;
		team_crypt.step(uni_t, uni_t.size());
		memcpy(buf, team_crypt.get_digest(), 16);
	}
	else
		memset(buf, 0, 16);
}

Config config;
<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2005-2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * This file is here to make all inlined functions also
 * available as non-inlines when building with GEOS_INLINES defined.
 *
 **********************************************************************/

// Only do something if GEOS_INLINE is defined
// Otherwise we'll end up with duplicated symbols
#ifdef GEOS_INLINE

// If using MingW with GEOS_INLINE to build a DLL then MingW's gcc
// has already generated the stubs for the contents of this file.
// Hence we need to supress it to avoid "multiple definition" errors
// during the final link phase
#if ! defined(__MINGW32__) || defined(__MINGW32__) && !defined(DLL_EXPORT)

// Undefine GEOS_INLINE so that .inl files
// will be ready for an implementation file
#undef GEOS_INLINE

#include <geos/inline.h>

#include <geos/io/WKTReader.inl>
#include <geos/io/ByteOrderDataInStream.inl>
#include <geos/operation/overlay/MinimalEdgeRing.inl>
#include <geos/geomgraph/DirectedEdge.inl>
#include <geos/geomgraph/GeometryGraph.inl>
#include <geos/algorithm/ConvexHull.inl>
#include <geos/geom/GeometryCollection.inl>
#include <geos/geom/LineSegment.inl>
#include <geos/geom/PrecisionModel.inl>
#include <geos/geom/Geometry.inl>
#include <geos/geom/Envelope.inl>
#include <geos/geom/Coordinate.inl>
#include <geos/geom/GeometryFactory.inl>
#include <geos/geom/MultiLineString.inl>
#include <geos/geom/MultiPolygon.inl>
#include <geos/geom/CoordinateArraySequenceFactory.inl>
#include <geos/noding/SegmentString.inl>
#include <geos/noding/snapround/HotPixel.inl>
#include <geos/noding/snapround/MCIndexSnapRounder.inl>
#include <geos/noding/MCIndexNoder.inl>

#endif // defined __MINGW32__ and !defined DLL_EXPORT

#endif // defined GEOS_INLINE
<commit_msg>Cygwin/Mingw patch from Mark Cave-Ayland<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2005-2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * This file is here to make all inlined functions also
 * available as non-inlines when building with GEOS_INLINES defined.
 *
 **********************************************************************/

// Only do something if GEOS_INLINE is defined
// Otherwise we'll end up with duplicated symbols
#ifdef GEOS_INLINE

// If using MingW or Cygwin with GEOS_INLINE to build a DLL then Win32 gcc
// has already generated the stubs for the contents of this file.
// Hence we need to supress it to avoid "multiple definition" errors
// during the final link phase
#if !(defined(__GNUC__) && defined(_WIN32)) || defined(__GNUC__) && defined(_WIN32) && !defined(DLL_EXPORT)

// Undefine GEOS_INLINE so that .inl files
// will be ready for an implementation file
#undef GEOS_INLINE

#include <geos/inline.h>

#include <geos/io/WKTReader.inl>
#include <geos/io/ByteOrderDataInStream.inl>
#include <geos/operation/overlay/MinimalEdgeRing.inl>
#include <geos/geomgraph/DirectedEdge.inl>
#include <geos/geomgraph/GeometryGraph.inl>
#include <geos/algorithm/ConvexHull.inl>
#include <geos/geom/GeometryCollection.inl>
#include <geos/geom/LineSegment.inl>
#include <geos/geom/PrecisionModel.inl>
#include <geos/geom/Geometry.inl>
#include <geos/geom/Envelope.inl>
#include <geos/geom/Coordinate.inl>
#include <geos/geom/GeometryFactory.inl>
#include <geos/geom/MultiLineString.inl>
#include <geos/geom/MultiPolygon.inl>
#include <geos/geom/CoordinateArraySequenceFactory.inl>
#include <geos/noding/SegmentString.inl>
#include <geos/noding/snapround/HotPixel.inl>
#include <geos/noding/snapround/MCIndexSnapRounder.inl>
#include <geos/noding/MCIndexNoder.inl>

#endif // defined __MINGW32__ and !defined DLL_EXPORT

#endif // defined GEOS_INLINE
<|endoftext|>


<commit_before>
#include <curl/curl.h>

#include <url/params.hpp>
#include <yadisk/client.hpp>
#include <boost/algorithm/string/join.hpp>
#include <sys/stat.h>
#include <fcntl.h>
#include <sstream>
using std::stringstream;

#include "callbacks.hpp"
#include "quote.hpp"

namespace yadisk
{
	static const std::string api_url = "https://cloud-api.yandex.net/v1/disk";

    Client::Client(string token_) : token{token_} {}
auto Client::upload(url::path to, fs::path from, bool overwrite, std::list<string> fields) -> json {
   	 CURL *curl;

  	struct stat file_info;

  	FILE *fd;
 	url::params_t url_params;
	struct curl_slist *header_list = nullptr;
	std::string auth_header;

 	fs::path p(fs::current_path());
	url_params["path"] = quote(to.string(), curl);
	url_params["overwrite"] = overwrite;
	url_params["fields"] = boost::algorithm::join(fields, ",");
	std::string url = api_url + "/upload?" + url_params.string();

	struct curl_slist *head_list = nullptr;
  	author_header = "Authorization: OAuth " + token;
	head_list = curl_slist_append(head_list, author_header.c_str());
  	stringstream res;
  	fd = fopen("C:\\file.txt", "w");  //открытие файла для загрузки
 	if(!fd)
    	return 1; //не может продолжить
   	// получаем размер файла
  	if(fstat(fileno(fd)), &file_info)!=0;
    	return 1; /* can't continue */

  	curl = curl_easy_init();
	//  if(curl) {
     	//выбор места для загрузки
    	curl_easy_setopt(curl, CURLOPT_URL,url.c_str());
    	curl_easy_setopt(curl, CURLOPT_READDATA, &res);
    	curl_easy_setopt(curl, CURLOPT_READFUNCTION, write<stringstream>);
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, head_list);

    	auto res_code = curl_easy_perform(curl);
     	curl_easy_cleanup(curl);
	curl_slist_free_all(header_list);
    	if (res_code != CURLE_OK) return json();

		auto answer = json::parse(res);
		return answer;

	curl = curl_easy_init();

    	 //загрузка по URL
    	curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
 	curl_easy_setopt(curl, CURLOPT_PUT, 1L);
     	//чтения файла
    	curl_easy_setopt(curl, CURLOPT_READDATA, fd);
    	//устанавливаем размер файла для отправки
    	curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,(curl_off_t)file_info.st_size);
     	//для облегчения трассировки
    	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

    	auto resp = curl_easy_perform(curl);
	curl_slist_free_all(head_list);
	curl_easy_cleanup(curl);
	if (response != CURLE_OK) return json();

		auto answer = json::parse(res);
		return answer;
     	return 0;
}

    auto Client::ping() -> bool {

        CURL * curl = curl_easy_init();
        if (curl == nullptr) return false;

        std::string url = api_url;

		struct curl_slist *header_list = nullptr;
		std::string auth_header = "Authorization: OAuth " + token;
		header_list = curl_slist_append(header_list, auth_header.c_str());

		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
        curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		auto response_code = curl_easy_perform(curl);

		curl_slist_free_all(header_list);
		curl_easy_cleanup(curl);

		if ( response_code != CURLE_OK ) return false;

        long http_response_code = 0;
		curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);

        return http_response_code == 200;
    }

	auto Client::copy(url::path from, url::path to, bool overwrite, std::list<std::string> fields) -> json {

		CURL * curl = curl_easy_init();
		if (!curl) return json();

		url::params_t url_params;
		url_params["from"] = quote(from.string(), curl);
		url_params["path"] = quote(to.string(), curl);
		url_params["overwrite"] = overwrite;
		url_params["fields"] = boost::algorithm::join(fields, ",");
		std::string url = api_url + "/resources/copy" + "?" + url_params.string();

		struct curl_slist *header_list = nullptr;
		std::string auth_header = "Authorization: OAuth " + token;
		header_list = curl_slist_append(header_list, auth_header.c_str());

		stringstream response;
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		curl_easy_setopt(curl, CURLOPT_READDATA, &response);
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, write<stringstream>);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		auto response_code = curl_easy_perform(curl);

		curl_slist_free_all(header_list);
		curl_easy_cleanup(curl);

		if (response_code != CURLE_OK) return json();

		auto response_data = json::parse(response);
		return response_data;
	}

	auto Client::patch(url::path resource, json meta, std::list<string> fields) -> json {

		// init http request
		CURL * curl = curl_easy_init();
		if (curl == nullptr) return json();

		// fill http url
		url::params_t url_params;
		url_params["fields"] = boost::algorithm::join(fields, ",");
		url_params["path"] = quote(resource.string(), curl);
		std::string url = api_url + "/resources" + "?" + url_params.string();

		// fill http headers
		curl_slist * header_list = nullptr;
		std::string auth_header = "Authorization: OAuth " + token;
		header_list = curl_slist_append(header_list, "Content-Type: application/json");
		header_list = curl_slist_append(header_list, auth_header.c_str());

		// fill http body
		auto request_body = meta.dump();

		// build http request
		stringstream response_body;
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write<stringstream>);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_body.c_str());
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request_body.size());
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		// perform http request
		auto response_code = curl_easy_perform(curl);

		// clean resources
		curl_slist_free_all(header_list);
		curl_easy_cleanup(curl);

		// check response code
		if ( response_code != CURLE_OK ) return json();

		// handle body of http response
		auto info = json::parse(response_body);
		return info;
	}
}

class curl_environment {
public:
    curl_environment() {
        curl_global_init(CURL_GLOBAL_ALL);
    }
    ~curl_environment() {
        curl_global_cleanup();
    }
};

static const curl_environment env;

<commit_msg>Update client.cpp<commit_after>
#include <curl/curl.h>

#include <url/params.hpp>
#include <yadisk/client.hpp>
#include <boost/algorithm/string/join.hpp>
#include <sys/stat.h>
#include <fcntl.h>
#include <sstream>
using std::stringstream;

#include "callbacks.hpp"
#include "quote.hpp"

namespace yadisk
{
	static const std::string api_url = "https://cloud-api.yandex.net/v1/disk";

    Client::Client(string token_) : token{token_} {}
auto Client::upload(url::path to, fs::path from, bool overwrite, std::list<string> fields) -> json {
   	 CURL *curl;

  	struct stat file_info;

  	FILE *fd;
 	url::params_t url_params;
	struct curl_slist *header_list = nullptr;
	std::string auth_header;

 	fs::path p(fs::current_path());
	url_params["path"] = quote(to.string(), curl);
	url_params["overwrite"] = overwrite;
	url_params["fields"] = boost::algorithm::join(fields, ",");
	std::string url = api_url + "/upload?" + url_params.string();

	struct curl_slist *head_list = nullptr;
  	auth_header = "Authorization: OAuth " + token;
	head_list = curl_slist_append(head_list, auth_header.c_str());
  	stringstream res;
  	fd = fopen("C:\\file.txt", "w");  //открытие файла для загрузки
 	if(!fd)
    	return 1; //не может продолжить
   	// получаем размер файла
  	if(fstat(fileno(fd), &file_info)!=0);
    	return 1; /* can't continue */

  	curl = curl_easy_init();
	//  if(curl) {
     	//выбор места для загрузки
    	curl_easy_setopt(curl, CURLOPT_URL,url.c_str());
    	curl_easy_setopt(curl, CURLOPT_READDATA, &res);
    	curl_easy_setopt(curl, CURLOPT_READFUNCTION, write<stringstream>);
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, head_list);

    	auto res_code = curl_easy_perform(curl);
     	curl_easy_cleanup(curl);
	curl_slist_free_all(header_list);
    	if (res_code != CURLE_OK) return json();

		auto answer = json::parse(res);
		return answer;

	curl = curl_easy_init();

    	 //загрузка по URL
    	curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
 	curl_easy_setopt(curl, CURLOPT_PUT, 1L);
     	//чтения файла
    	curl_easy_setopt(curl, CURLOPT_READDATA, fd);
    	//устанавливаем размер файла для отправки
    	curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,(curl_off_t)file_info.st_size);
     	//для облегчения трассировки
    	curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

    	auto resp = curl_easy_perform(curl);
	curl_slist_free_all(head_list);
	curl_easy_cleanup(curl);
	if (resp != CURLE_OK) return json();

		auto answer = json::parse(res);
		return answer;
     	return 0;
}

    auto Client::ping() -> bool {

        CURL * curl = curl_easy_init();
        if (curl == nullptr) return false;

        std::string url = api_url;

		struct curl_slist *header_list = nullptr;
		std::string auth_header = "Authorization: OAuth " + token;
		header_list = curl_slist_append(header_list, auth_header.c_str());

		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
        curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		auto response_code = curl_easy_perform(curl);

		curl_slist_free_all(header_list);
		curl_easy_cleanup(curl);

		if ( response_code != CURLE_OK ) return false;

        long http_response_code = 0;
		curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);

        return http_response_code == 200;
    }

	auto Client::copy(url::path from, url::path to, bool overwrite, std::list<std::string> fields) -> json {

		CURL * curl = curl_easy_init();
		if (!curl) return json();

		url::params_t url_params;
		url_params["from"] = quote(from.string(), curl);
		url_params["path"] = quote(to.string(), curl);
		url_params["overwrite"] = overwrite;
		url_params["fields"] = boost::algorithm::join(fields, ",");
		std::string url = api_url + "/resources/copy" + "?" + url_params.string();

		struct curl_slist *header_list = nullptr;
		std::string auth_header = "Authorization: OAuth " + token;
		header_list = curl_slist_append(header_list, auth_header.c_str());

		stringstream response;
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		curl_easy_setopt(curl, CURLOPT_READDATA, &response);
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, write<stringstream>);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		auto response_code = curl_easy_perform(curl);

		curl_slist_free_all(header_list);
		curl_easy_cleanup(curl);

		if (response_code != CURLE_OK) return json();

		auto response_data = json::parse(response);
		return response_data;
	}

	auto Client::patch(url::path resource, json meta, std::list<string> fields) -> json {

		// init http request
		CURL * curl = curl_easy_init();
		if (curl == nullptr) return json();

		// fill http url
		url::params_t url_params;
		url_params["fields"] = boost::algorithm::join(fields, ",");
		url_params["path"] = quote(resource.string(), curl);
		std::string url = api_url + "/resources" + "?" + url_params.string();

		// fill http headers
		curl_slist * header_list = nullptr;
		std::string auth_header = "Authorization: OAuth " + token;
		header_list = curl_slist_append(header_list, "Content-Type: application/json");
		header_list = curl_slist_append(header_list, auth_header.c_str());

		// fill http body
		auto request_body = meta.dump();

		// build http request
		stringstream response_body;
		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write<stringstream>);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_body.c_str());
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request_body.size());
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);

		// perform http request
		auto response_code = curl_easy_perform(curl);

		// clean resources
		curl_slist_free_all(header_list);
		curl_easy_cleanup(curl);

		// check response code
		if ( response_code != CURLE_OK ) return json();

		// handle body of http response
		auto info = json::parse(response_body);
		return info;
	}
}

class curl_environment {
public:
    curl_environment() {
        curl_global_init(CURL_GLOBAL_ALL);
    }
    ~curl_environment() {
        curl_global_cleanup();
    }
};

static const curl_environment env;

<|endoftext|>


<commit_before>#include "matrix.hpp"

Matrix::Matrix(int length) {
	row = length;
	col = length;

	mas = new int*[row];
	for (int i = 0; i < row; i++) {
		mas[i] = new int[col];
		for (int j = 0; j < col; j++) {
			mas[i][j] = 0;
		}
	}
}

Matrix::Matrix(int r, int c) {
	row = r;
	col = c;

	mas = new int*[row];
	for (int i = 0; i < row; i++) {
		mas[i] = new int[col];
	}
}

Matrix::~Matrix() {
	for (int i = 0; i < row; i++) {
		delete[] mas[i];
	}

	delete[] mas;
}

Matrix::Matrix(const Matrix&a) {
	row = a.row;
	col = a.col;

	mas = new int*[row];
	for (int i = 0; i < row; i++) {
		mas[i] = new int[col];
		for (int j = 0; j < col; j++) {
			mas[i][j] = a.mas[i][j];
		}
	}
}

void Matrix::fill( const char*file) {
	ifstream fin1(file);
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			fin1 >> mas[i][j];
		}
	}
}

void Matrix::show() const {

	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			cout << mas[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
}

Matrix Matrix::operator+(const Matrix& a) const {

	Matrix help(row, col);

	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			help.mas[i][j] = mas[i][j] + a.mas[i][j];
		}
	}
	return help;
}

Matrix Matrix::operator*(const Matrix& a) const {

	Matrix help(row, col);

	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			help.mas[i][j] = 0;
			for (int k = 0; k < col; k++) {
				help.mas[i][j] += mas[i][k] * a.mas[k][j];
			}
		}
	}
	return help;
}

int Matrix::rows() {
	return row;
}

int Matrix::columns() {
	return col;
}

	int operator[](int x, int y) const {
		return mas[x][y];
	}

<commit_msg>Update matrix.cpp<commit_after>#include "matrix.hpp"

Matrix::Matrix(int length) {
	row = length;
	col = length;

	mas = new int*[row];
	for (int i = 0; i < row; i++) {
		mas[i] = new int[col];
		for (int j = 0; j < col; j++) {
			mas[i][j] = 0;
		}
	}
}

Matrix::Matrix(int r, int c) {
	row = r;
	col = c;

	mas = new int*[row];
	for (int i = 0; i < row; i++) {
		mas[i] = new int[col];
	}
}

Matrix::~Matrix() {
	for (int i = 0; i < row; i++) {
		delete[] mas[i];
	}

	delete[] mas;
}

Matrix::Matrix(const Matrix&a) {
	row = a.row;
	col = a.col;

	mas = new int*[row];
	for (int i = 0; i < row; i++) {
		mas[i] = new int[col];
		for (int j = 0; j < col; j++) {
			mas[i][j] = a.mas[i][j];
		}
	}
}

void Matrix::fill( const char*file) {
	ifstream fin1(file);
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			fin1 >> mas[i][j];
		}
	}
}

void Matrix::show() const {

	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			cout << mas[i][j] << " ";
		}
		cout << endl;
	}
	cout << endl;
}

Matrix Matrix::operator+(const Matrix& a) const {

	Matrix help(row, col);

	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			help.mas[i][j] = mas[i][j] + a.mas[i][j];
		}
	}
	return help;
}

Matrix Matrix::operator*(const Matrix& a) const {

	Matrix help(row, col);

	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			help.mas[i][j] = 0;
			for (int k = 0; k < col; k++) {
				help.mas[i][j] += mas[i][k] * a.mas[k][j];
			}
		}
	}
	return help;
}

int Matrix::rows() {
	return row;
}

int Matrix::columns() {
	return col;
}

int Element(int i, int j)
        {
            if (i<row && j<col)
                return mas[i][j];
            else
                cout << "Error: 1";
        }

<|endoftext|>