<commit_before>//===---- LoadStoreOpts.cpp - SIL Load/Store Optimizations Forwarding  ----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This pass eliminates redundent loads, dead stores, and performs load
// forwarding.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "load-store-opts"
#include "swift/SILPasses/Passes.h"
#include "swift/SIL/Projection.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace swift;

STATISTIC(NumDeadStores,     "Number of dead stores removed");
STATISTIC(NumDupLoads,       "Number of dup loads removed");
STATISTIC(NumForwardedLoads, "Number of loads forwarded");

//===----------------------------------------------------------------------===//
//                             Utility Functions
//===----------------------------------------------------------------------===//

/// Given the already emitted load PrevLI, see if we can find a projection
/// address path to LI. If we can, emit the corresponding aggregate projection
/// insts and return the last such inst.
static SILValue findExtractPathBetweenValues(LoadInst *PrevLI, LoadInst *LI) {
  // Attempt to find the projection path from LI -> PrevLI.
  SILValue PrevLIOp = PrevLI->getOperand();
  SILValue LIOp = LI->getOperand();
  llvm::SmallVector<Projection, 4> ProjectionPath;

  // If we failed to find the path, return an empty value early.
  if (!findAddressProjectionPathBetweenValues(PrevLIOp, LIOp, ProjectionPath))
    return SILValue();

  // If we found a projection path, but there are no projections, then the two
  // loads must be the same, return PrevLI.
  if (ProjectionPath.empty())
    return PrevLI;

  // Ok, at this point we know that we can construct our aggregate projections
  // from our list of address projections.
  SILValue LastExtract = PrevLI;
  SILBuilder Builder(LI);
  while (!ProjectionPath.empty()) {
    auto P = ProjectionPath.pop_back_val();
    if (auto *D = P.getDecl()) {
      assert(P.getNominalType() != Projection::NominalType::Class &&
             "Aggregate projections do not exist for classes.");
      LastExtract = Builder.createStructExtract(LI->getLoc(), LastExtract,
                                                D,
                                                P.getType().getObjectType());
      assert(cast<StructExtractInst>(*LastExtract).getStructDecl() &&
             "Instruction must have a struct decl!");
    } else {
      LastExtract = Builder.createTupleExtract(LI->getLoc(), LastExtract,
                                               P.getIndex(),
                                               P.getType().getObjectType());
      assert(cast<TupleExtractInst>(*LastExtract).getTupleType() &&
             "Instruction must have a tuple type!");
    }
  }

  // Return the last extract we created.
  return LastExtract;
}

static void
invalidateAliasingLoads(SILInstruction *Inst,
                        llvm::SmallPtrSetImpl<LoadInst *> &Loads,
                        AliasAnalysis *AA) {
  llvm::SmallVector<LoadInst *, 4> InvalidatedLoadList;
  for (auto *LI : Loads)
    if (AA->mayWriteToMemory(Inst, LI->getOperand()))
      InvalidatedLoadList.push_back(LI);
  for (auto *LI : InvalidatedLoadList) {
    DEBUG(llvm::dbgs() << "    Found an instruction that writes to memory "
          "such that a load is invalidated:" << *LI);
    Loads.erase(LI);
  }
}

//===----------------------------------------------------------------------===//
//                               Implementation
//===----------------------------------------------------------------------===//

/// \brief Promote stored values to loads, remove dead stores and merge
/// duplicated loads.
bool performLoadStoreOptimizations(SILBasicBlock *BB, AliasAnalysis *AA) {
  bool Changed = false;
  StoreInst *PrevStore = nullptr;

  // This is a list of LoadInst instructions that reference memory locations
  // were not clobbered by instructions that write to memory. In other words
  // the SSA value of the load is known to be the same value as the referenced
  // pointer. The values in the list are potentially updated on each iteration
  // of the loop below.
  llvm::SmallPtrSet<LoadInst *, 8> Loads;

  auto II = BB->begin(), E = BB->end();
  while (II != E) {
    SILInstruction *Inst = II++;

    DEBUG(llvm::dbgs() << "Visiting: " << *Inst);

    // This is a StoreInst. Let's see if we can remove the previous stores.
    if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {

      // If we are storing a value that is available in the load list then we
      // know that no one clobbered that address and the current store is
      // redundant and we can remove it.
      if (LoadInst *LdSrc = dyn_cast<LoadInst>(SI->getSrc())) {
        // Check that the loaded value is live and that the destination address
        // is the same as the loaded address.
        if (Loads.count(LdSrc) && LdSrc->getOperand() == SI->getDest()) {
          Changed = true;
          recursivelyDeleteTriviallyDeadInstructions(SI, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
          NumDeadStores++;
          continue;
        }
      }

      // Invalidate any load that we can not prove does not read from the stores
      // destination.
      invalidateAliasingLoads(Inst, Loads, AA);

      // If we are storing to the previously stored address then delete the old
      // store.
      if (PrevStore && PrevStore->getDest() == SI->getDest()) {
        DEBUG(llvm::dbgs() << "    Found a dead previous store... Removing...:"
              << *PrevStore);
        Changed = true;
        recursivelyDeleteTriviallyDeadInstructions(PrevStore, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
        PrevStore = SI;
        NumDeadStores++;
        continue;
      }
      PrevStore = SI;
      continue;
    }

    if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
      // If we are loading a value that we just saved then use the saved value.
      if (PrevStore && PrevStore->getDest() == LI->getOperand()) {
        DEBUG(llvm::dbgs() << "    Forwarding store from: " << *PrevStore);
        SILValue(LI, 0).replaceAllUsesWith(PrevStore->getSrc());
        recursivelyDeleteTriviallyDeadInstructions(LI, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
        Changed = true;
        NumForwardedLoads++;
        continue;
      }

      // Promote partial loads.
      // Check that we are loading a struct element:
      if (auto *SEAI = dyn_cast<StructElementAddrInst>(LI->getOperand())) {
        // And that the previous store stores into that struct.
        if (PrevStore && PrevStore->getDest() == SEAI->getOperand()) {
          // And that the stored value is a struct construction instruction:
          if (auto *SI = dyn_cast<StructInst>(PrevStore->getSrc())) {
            DEBUG(llvm::dbgs() << "    Forwarding element store from: " <<
                  *PrevStore);
            unsigned FieldNo = SEAI->getFieldNo();
            SILValue(LI, 0).replaceAllUsesWith(SI->getOperand(FieldNo));
            recursivelyDeleteTriviallyDeadInstructions(LI, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
            Changed = true;
            NumForwardedLoads++;
            continue;
          }
        }
      }

      // Search the previous loads and replace the current load with one of the
      // previous loads.
      for (auto PrevLI : Loads) {
        SILValue ForwardingExtract = findExtractPathBetweenValues(PrevLI, LI);
        if (!ForwardingExtract)
          continue;

        DEBUG(llvm::dbgs() << "    Replacing with previous load: "
              << *ForwardingExtract);
        SILValue(LI, 0).replaceAllUsesWith(ForwardingExtract);
        recursivelyDeleteTriviallyDeadInstructions(LI, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
        Changed = true;
        LI = nullptr;
        NumDupLoads++;
        break;
      }

      if (LI)
        Loads.insert(LI);
      continue;
    }

    // Retains write to memory but they don't affect loads and stores.
    if (isa<StrongRetainInst>(Inst)) {
      DEBUG(llvm::dbgs() << "    Found strong retain, does not affect loads and"
            " stores.\n");
      continue;
    }

    // Dealloc stack does not affect loads and stores.
    if (isa<DeallocStackInst>(Inst)) {
      DEBUG(llvm::dbgs() << "Found a dealloc stack. Does not affect loads and "
            "stores.\n");
      continue;
    }

    if (auto *AI = dyn_cast<ApplyInst>(Inst))
      if (auto *BI = dyn_cast<BuiltinFunctionRefInst>(&*AI->getCallee()))
        if (isReadNone(BI)) {
          DEBUG(llvm::dbgs() << "    Found readnone builtin, does not affect "
                "loads and stores.\n");
          continue;
        }

    // cond_fail does not read/write memory in a manner that we care about.
    if (isa<CondFailInst>(Inst)) {
      DEBUG(llvm::dbgs() << "    Found a cond fail, does not affect "
            "loads and stores.\n");
      continue;
    }

    // All other instructions that read from memory invalidate the store.
    if (Inst->mayReadFromMemory()) {
      DEBUG(llvm::dbgs() << "    Found an instruction that reads from memory."
            " Invalidating store.\n");
      PrevStore = nullptr;
    }

    // If we have an instruction that may write to memory and we can not prove
    // that it and its operands can not alias a load we have visited, invalidate
    // that load.
    if (Inst->mayWriteToMemory()) {
      // Invalidate any load that we can not prove does not read from one of the
      // writing instructions operands.
      invalidateAliasingLoads(Inst, Loads, AA);
      PrevStore = nullptr;
    }
  }

  return Changed;
}

//===----------------------------------------------------------------------===//
//                           Top Level Entry Point
//===----------------------------------------------------------------------===//

namespace {

class LoadStoreOpts : public SILFunctionTransform {

  /// The entry point to the transformation.
  void run() {
    SILFunction &F = *getFunction();

    DEBUG(llvm::dbgs() << "***** Load Store Elimination on function: "
          << F.getName() << " *****\n");

    AliasAnalysis *AA = PM->getAnalysis<AliasAnalysis>();

    // Remove dead stores, merge duplicate loads, and forward stores to loads.
    bool Changed = false;
    for (auto &BB : F)
      Changed |= performLoadStoreOptimizations(&BB, AA);

    if (Changed)
      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
  }

  StringRef getName() override { return "SIL Load Store Opts"; }
};

} // end anonymous namespace

SILTransform *swift::createLoadStoreOpts() {
  return new LoadStoreOpts();
}
<commit_msg>[load-store-opts] Keeping performing load store optimizations on a basic block until we no longer eliminate anything.<commit_after>//===---- LoadStoreOpts.cpp - SIL Load/Store Optimizations Forwarding  ----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This pass eliminates redundent loads, dead stores, and performs load
// forwarding.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "load-store-opts"
#include "swift/SILPasses/Passes.h"
#include "swift/SIL/Projection.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "swift/SILPasses/Utils/Local.h"
#include "swift/SILPasses/Transforms.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace swift;

STATISTIC(NumDeadStores,     "Number of dead stores removed");
STATISTIC(NumDupLoads,       "Number of dup loads removed");
STATISTIC(NumForwardedLoads, "Number of loads forwarded");

//===----------------------------------------------------------------------===//
//                             Utility Functions
//===----------------------------------------------------------------------===//

/// Given the already emitted load PrevLI, see if we can find a projection
/// address path to LI. If we can, emit the corresponding aggregate projection
/// insts and return the last such inst.
static SILValue findExtractPathBetweenValues(LoadInst *PrevLI, LoadInst *LI) {
  // Attempt to find the projection path from LI -> PrevLI.
  SILValue PrevLIOp = PrevLI->getOperand();
  SILValue LIOp = LI->getOperand();
  llvm::SmallVector<Projection, 4> ProjectionPath;

  // If we failed to find the path, return an empty value early.
  if (!findAddressProjectionPathBetweenValues(PrevLIOp, LIOp, ProjectionPath))
    return SILValue();

  // If we found a projection path, but there are no projections, then the two
  // loads must be the same, return PrevLI.
  if (ProjectionPath.empty())
    return PrevLI;

  // Ok, at this point we know that we can construct our aggregate projections
  // from our list of address projections.
  SILValue LastExtract = PrevLI;
  SILBuilder Builder(LI);
  while (!ProjectionPath.empty()) {
    auto P = ProjectionPath.pop_back_val();
    if (auto *D = P.getDecl()) {
      assert(P.getNominalType() != Projection::NominalType::Class &&
             "Aggregate projections do not exist for classes.");
      LastExtract = Builder.createStructExtract(LI->getLoc(), LastExtract,
                                                D,
                                                P.getType().getObjectType());
      assert(cast<StructExtractInst>(*LastExtract).getStructDecl() &&
             "Instruction must have a struct decl!");
    } else {
      LastExtract = Builder.createTupleExtract(LI->getLoc(), LastExtract,
                                               P.getIndex(),
                                               P.getType().getObjectType());
      assert(cast<TupleExtractInst>(*LastExtract).getTupleType() &&
             "Instruction must have a tuple type!");
    }
  }

  // Return the last extract we created.
  return LastExtract;
}

static void
invalidateAliasingLoads(SILInstruction *Inst,
                        llvm::SmallPtrSetImpl<LoadInst *> &Loads,
                        AliasAnalysis *AA) {
  llvm::SmallVector<LoadInst *, 4> InvalidatedLoadList;
  for (auto *LI : Loads)
    if (AA->mayWriteToMemory(Inst, LI->getOperand()))
      InvalidatedLoadList.push_back(LI);
  for (auto *LI : InvalidatedLoadList) {
    DEBUG(llvm::dbgs() << "    Found an instruction that writes to memory "
          "such that a load is invalidated:" << *LI);
    Loads.erase(LI);
  }
}

//===----------------------------------------------------------------------===//
//                               Implementation
//===----------------------------------------------------------------------===//

/// \brief Promote stored values to loads, remove dead stores and merge
/// duplicated loads.
bool performLoadStoreOptimizations(SILBasicBlock *BB, AliasAnalysis *AA) {
  bool Changed = false;
  StoreInst *PrevStore = nullptr;

  // This is a list of LoadInst instructions that reference memory locations
  // were not clobbered by instructions that write to memory. In other words
  // the SSA value of the load is known to be the same value as the referenced
  // pointer. The values in the list are potentially updated on each iteration
  // of the loop below.
  llvm::SmallPtrSet<LoadInst *, 8> Loads;

  auto II = BB->begin(), E = BB->end();
  while (II != E) {
    SILInstruction *Inst = II++;

    DEBUG(llvm::dbgs() << "Visiting: " << *Inst);

    // This is a StoreInst. Let's see if we can remove the previous stores.
    if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {

      // If we are storing a value that is available in the load list then we
      // know that no one clobbered that address and the current store is
      // redundant and we can remove it.
      if (LoadInst *LdSrc = dyn_cast<LoadInst>(SI->getSrc())) {
        // Check that the loaded value is live and that the destination address
        // is the same as the loaded address.
        if (Loads.count(LdSrc) && LdSrc->getOperand() == SI->getDest()) {
          Changed = true;
          recursivelyDeleteTriviallyDeadInstructions(SI, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
          NumDeadStores++;
          continue;
        }
      }

      // Invalidate any load that we can not prove does not read from the stores
      // destination.
      invalidateAliasingLoads(Inst, Loads, AA);

      // If we are storing to the previously stored address then delete the old
      // store.
      if (PrevStore && PrevStore->getDest() == SI->getDest()) {
        DEBUG(llvm::dbgs() << "    Found a dead previous store... Removing...:"
              << *PrevStore);
        Changed = true;
        recursivelyDeleteTriviallyDeadInstructions(PrevStore, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
        PrevStore = SI;
        NumDeadStores++;
        continue;
      }
      PrevStore = SI;
      continue;
    }

    if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
      // If we are loading a value that we just saved then use the saved value.
      if (PrevStore && PrevStore->getDest() == LI->getOperand()) {
        DEBUG(llvm::dbgs() << "    Forwarding store from: " << *PrevStore);
        SILValue(LI, 0).replaceAllUsesWith(PrevStore->getSrc());
        recursivelyDeleteTriviallyDeadInstructions(LI, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
        Changed = true;
        NumForwardedLoads++;
        continue;
      }

      // Promote partial loads.
      // Check that we are loading a struct element:
      if (auto *SEAI = dyn_cast<StructElementAddrInst>(LI->getOperand())) {
        // And that the previous store stores into that struct.
        if (PrevStore && PrevStore->getDest() == SEAI->getOperand()) {
          // And that the stored value is a struct construction instruction:
          if (auto *SI = dyn_cast<StructInst>(PrevStore->getSrc())) {
            DEBUG(llvm::dbgs() << "    Forwarding element store from: " <<
                  *PrevStore);
            unsigned FieldNo = SEAI->getFieldNo();
            SILValue(LI, 0).replaceAllUsesWith(SI->getOperand(FieldNo));
            recursivelyDeleteTriviallyDeadInstructions(LI, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
            Changed = true;
            NumForwardedLoads++;
            continue;
          }
        }
      }

      // Search the previous loads and replace the current load with one of the
      // previous loads.
      for (auto PrevLI : Loads) {
        SILValue ForwardingExtract = findExtractPathBetweenValues(PrevLI, LI);
        if (!ForwardingExtract)
          continue;

        DEBUG(llvm::dbgs() << "    Replacing with previous load: "
              << *ForwardingExtract);
        SILValue(LI, 0).replaceAllUsesWith(ForwardingExtract);
        recursivelyDeleteTriviallyDeadInstructions(LI, true,
                                [&](SILInstruction *DeadI) {
                                  if (LoadInst *LI = dyn_cast<LoadInst>(DeadI))
                                    Loads.erase(LI);
                                });
        Changed = true;
        LI = nullptr;
        NumDupLoads++;
        break;
      }

      if (LI)
        Loads.insert(LI);
      continue;
    }

    // Retains write to memory but they don't affect loads and stores.
    if (isa<StrongRetainInst>(Inst)) {
      DEBUG(llvm::dbgs() << "    Found strong retain, does not affect loads and"
            " stores.\n");
      continue;
    }

    // Dealloc stack does not affect loads and stores.
    if (isa<DeallocStackInst>(Inst)) {
      DEBUG(llvm::dbgs() << "Found a dealloc stack. Does not affect loads and "
            "stores.\n");
      continue;
    }

    if (auto *AI = dyn_cast<ApplyInst>(Inst))
      if (auto *BI = dyn_cast<BuiltinFunctionRefInst>(&*AI->getCallee()))
        if (isReadNone(BI)) {
          DEBUG(llvm::dbgs() << "    Found readnone builtin, does not affect "
                "loads and stores.\n");
          continue;
        }

    // cond_fail does not read/write memory in a manner that we care about.
    if (isa<CondFailInst>(Inst)) {
      DEBUG(llvm::dbgs() << "    Found a cond fail, does not affect "
            "loads and stores.\n");
      continue;
    }

    // All other instructions that read from memory invalidate the store.
    if (Inst->mayReadFromMemory()) {
      DEBUG(llvm::dbgs() << "    Found an instruction that reads from memory."
            " Invalidating store.\n");
      PrevStore = nullptr;
    }

    // If we have an instruction that may write to memory and we can not prove
    // that it and its operands can not alias a load we have visited, invalidate
    // that load.
    if (Inst->mayWriteToMemory()) {
      // Invalidate any load that we can not prove does not read from one of the
      // writing instructions operands.
      invalidateAliasingLoads(Inst, Loads, AA);
      PrevStore = nullptr;
    }
  }

  return Changed;
}

//===----------------------------------------------------------------------===//
//                           Top Level Entry Point
//===----------------------------------------------------------------------===//

namespace {

class LoadStoreOpts : public SILFunctionTransform {

  /// The entry point to the transformation.
  void run() {
    SILFunction &F = *getFunction();

    DEBUG(llvm::dbgs() << "***** Load Store Elimination on function: "
          << F.getName() << " *****\n");

    AliasAnalysis *AA = PM->getAnalysis<AliasAnalysis>();

    // Remove dead stores, merge duplicate loads, and forward stores to loads.
    bool Changed = false;
    for (auto &BB : F)
      while (performLoadStoreOptimizations(&BB, AA))
        Changed = true;

    if (Changed)
      invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
  }

  StringRef getName() override { return "SIL Load Store Opts"; }
};

} // end anonymous namespace

SILTransform *swift::createLoadStoreOpts() {
  return new LoadStoreOpts();
}
<|endoftext|>


<commit_before>/////////////////////////////////////////
//
//             OpenLieroX
//
//   work by JasonB
//   code under LGPL
//   enhanced by Dark Charlie and Albert Zeyer
//
//
/////////////////////////////////////////

// Network Channel class
// Created 16/6/01
// Jason Boettcher

#include <iostream>

#include "LieroX.h"
#include "CChannel.h"
#include "StringUtils.h"
#include "Timer.h"

using namespace std;

// default max size for UDP packets for windows is 1280
// only a size of 512 is guaranteed
#define MAX_PACKET_SIZE 512
#define RELIABLE_HEADER_LEN 8

///////////////////
// Setup the channel
void CChannel::Create(NetworkAddr *_adr, int _port, NetworkSocket _sock)
{
	RemoteAddr = *_adr;
	iPort = _port;
	fLastPckRecvd = tLX->fCurTime;
	Socket = _sock;
	Reliable.Clear();
	Messages.clear();
	iPacketsDropped=0;
	iPacketsGood=0;
	fLastSent = tLX->fCurTime-1;
	fLastPingSent = fLastSent;
	fIncomingClearTime = -9999;
	fOutgoingClearTime = -9999;
	fIncomingRate = 0;
	fOutgoingRate = 0;
	iCurrentIncomingBytes = 0;
	iCurrentOutgoingBytes = 0;
	iPongSequence = -1;
	iPing = 0;
	bNewReliablePacket = false;

	// Clear the sequences
	iIncomingSequence = 0;
	iIncomingAcknowledged = 0;
	iIncoming_ReliableAcknowledged = 0;
	iIncoming_ReliableSequence = 0;
	iOutgoingSequence = 0;
	iReliableSequence = 0;
	iLast_ReliableSequence = 0;
	iOutgoingBytes = 0;
	iIncomingBytes = 0;
}

////////////////////
// Adds a packet to reliable queue
void CChannel::AddReliablePacketToSend(CBytestream& bs)
{
	if (bs.GetLength() > MAX_PACKET_SIZE - RELIABLE_HEADER_LEN)  {
		printf("ERROR: trying to send a reliable packet of size " + itoa(bs.GetLength()) +
			" which is bigger than allowed size (" + itoa(MAX_PACKET_SIZE - RELIABLE_HEADER_LEN) +
			"), packet might not be sent at all!\n");
		Messages.push_back(bs); // Try to send it anyway, perhaps we're lucky...
		return;
	}

	// If no messages at all, add the first one
	if (Messages.size() == 0)  {
		Messages.push_back(bs);
		return;
	}

	// Some reliable messages already in queue, see if we should already split the packet
	if (bs.GetLength() + (Messages.rbegin()->GetLength()) > MAX_PACKET_SIZE)
		Messages.push_back(bs);
	else
		Messages.rbegin()->Append(&bs);
}

///////////////////
// Transmitt data, as well as handling reliable packets
void CChannel::Transmit( CBytestream *bs )
{
	CBytestream outpack;
	Uint32 SendReliable = 0;
	ulong r1,r2;

	// If the remote side dropped the last reliable packet, re-send it
	if(iIncomingAcknowledged > iLast_ReliableSequence && iIncoming_ReliableAcknowledged != iReliableSequence)  {
//		printf("Remote side dropped a reliable packet, resending...\n");
		SendReliable = 1;
	}

	// We send reliable message in these cases:
	// 1. The reliable buffer is empty, we copy the reliable message into it and send it
	// 2. We need to refresh ping
	if(Reliable.GetLength() == 0 && (Messages.size() > 0 || (tLX->fCurTime - fLastPingSent >= 1.0f && iPongSequence == -1))) {
		if (Messages.size() > 0)  {
			Reliable = *Messages.begin();
			Messages.erase(Messages.begin());
		}

		// We got a reliable packet to send
		SendReliable = 1;

		// XOR the reliable sequence
		iReliableSequence ^= 1;
	}

	// Create the reliable packet header
	r1 = iOutgoingSequence | (SendReliable << 31);
	r2 = iIncomingSequence | (iIncoming_ReliableSequence << 31);

	iOutgoingSequence++;

	outpack.writeInt(r1,4);
	outpack.writeInt(r2,4);

	// If were sending a reliable message, send it first
	if(SendReliable) {
		outpack.Append(&Reliable);
		iLast_ReliableSequence = iOutgoingSequence;

		// If we are sending a reliable message, remember this time and use it for ping calculations
		if (iPongSequence == -1)  {
			iPongSequence = iOutgoingSequence;
			fLastPingSent = GetMilliSeconds();
		}

	}

	// And add on the un reliable data if room in the packet struct
	if(bs) {
		if(outpack.GetLength() + bs->GetLength() < MAX_PACKET_SIZE) // Backward compatibility
			outpack.Append(bs);
	}

	// Send the packet
	SetRemoteNetAddr(Socket, RemoteAddr);
	outpack.Send(Socket);

	// Update statistics
	iOutgoingBytes += outpack.GetLength();
	iCurrentOutgoingBytes += outpack.GetLength();
	fLastSent = tLX->fCurTime;

	// Calculate the bytes per second
	if (tLX->fCurTime - fOutgoingClearTime >= 2.0f)  {
		fOutgoingRate = (float)iCurrentOutgoingBytes/(GetMilliSeconds() - fOutgoingClearTime);
		iCurrentOutgoingBytes = 0;
		fOutgoingClearTime = GetMilliSeconds();
	}
}

///////////////////
// Process channel (after receiving data)
bool CChannel::Process(CBytestream *bs)
{
	Uint32 Sequence, SequenceAck;
	Uint32 ReliableAck, ReliableMessage;
	int drop;

	// Start from the beginning of the packet
	bs->ResetPosToBegin();

	// Read the reliable packet header
	Sequence = bs->readInt(4);
	SequenceAck = bs->readInt(4);

	// Get the reliable bits
	ReliableMessage = Sequence >> 31;
	ReliableAck = SequenceAck >> 31;

	// Get rid of the reliable bits
	Sequence &= ~(1<<31);
	SequenceAck &= ~(1<<31);

	// Calculate the bytes per second
	iIncomingBytes += bs->GetRestLen();
	iCurrentIncomingBytes += bs->GetRestLen();
	if (tLX->fCurTime - fIncomingClearTime >= 2.0f)  {
		fIncomingRate = (float)iCurrentIncomingBytes/(GetMilliSeconds() - fIncomingClearTime);
		iCurrentIncomingBytes = 0;
		fIncomingClearTime = GetMilliSeconds();
	}

	// Get rid of the old packets
	// Small hack: there's a bug in old clients causing the first packet being ignored and resent later
	// It caused a delay when joining (especially on high-ping servers), this hack improves it
	if((Sequence <= iIncomingSequence) && (Sequence != 0 && iIncomingSequence != 0)) {
//		printf("Warning: Packet dropped\n");
//		bs->Dump();
		/*
		If we didn't ignore it here, we would become it
		again (the remote side will resend it because it thinks we've dropped
		the packet) and then parse it again => doubled text etc */
		// see GameServer::ReadPackets and CClient::ReadPackets
		// or perhaps it's ok to return true here but we should change the behaviour in *::ReadPackets
		return false;
	}

	// Check for dropped packets
	drop = Sequence - (iIncomingSequence+1);
	if(drop>0)
		// Update statistics
		iPacketsDropped++;

	// If the outgoing reliable message has been acknowledged, clear it for more reliable messages
	if(ReliableAck == iReliableSequence)
		Reliable.Clear();

	// Check if pong has been acknowledged
	if(SequenceAck >= (size_t)iPongSequence)  {
		iPongSequence = -1;  // Ready for new pinging
		iPing = MAX(0, (int)((tLX->fCurTime - fLastPingSent) * 1000));
	}

	// If this packet contained a reliable message, update the sequences
	iIncomingSequence = Sequence;
	iIncomingAcknowledged = SequenceAck;
	iIncoming_ReliableAcknowledged = ReliableAck;
	if(ReliableMessage)  {
		iIncoming_ReliableSequence ^= 1;
		bNewReliablePacket = true;
	} else
		bNewReliablePacket = false;

	// Update the statistics
	fLastPckRecvd = GetMilliSeconds();
	iPacketsGood++;

	return true;
}
<commit_msg>small cleanup<commit_after>/////////////////////////////////////////
//
//             OpenLieroX
//
//   work by JasonB
//   code under LGPL
//   enhanced by Dark Charlie and Albert Zeyer
//
//
/////////////////////////////////////////

// Network Channel class
// Created 16/6/01
// Jason Boettcher

#include <iostream>

#include "LieroX.h"
#include "CChannel.h"
#include "StringUtils.h"
#include "Timer.h"

using namespace std;

// default max size for UDP packets for windows is 1280
// only a size of 512 is guaranteed
#define MAX_PACKET_SIZE 512
#define RELIABLE_HEADER_LEN 8

///////////////////
// Setup the channel
void CChannel::Create(NetworkAddr *_adr, int _port, NetworkSocket _sock)
{
	RemoteAddr = *_adr;
	iPort = _port;
	fLastPckRecvd = tLX->fCurTime;
	Socket = _sock;
	Reliable.Clear();
	Messages.clear();
	iPacketsDropped=0;
	iPacketsGood=0;
	fLastSent = tLX->fCurTime-1;
	fLastPingSent = fLastSent;
	fIncomingClearTime = -9999;
	fOutgoingClearTime = -9999;
	fIncomingRate = 0;
	fOutgoingRate = 0;
	iCurrentIncomingBytes = 0;
	iCurrentOutgoingBytes = 0;
	iPongSequence = -1;
	iPing = 0;
	bNewReliablePacket = false;

	// Clear the sequences
	iIncomingSequence = 0;
	iIncomingAcknowledged = 0;
	iIncoming_ReliableAcknowledged = 0;
	iIncoming_ReliableSequence = 0;
	iOutgoingSequence = 0;
	iReliableSequence = 0;
	iLast_ReliableSequence = 0;
	iOutgoingBytes = 0;
	iIncomingBytes = 0;
}

////////////////////
// Adds a packet to reliable queue
void CChannel::AddReliablePacketToSend(CBytestream& bs)
{
	if (bs.GetLength() > MAX_PACKET_SIZE - RELIABLE_HEADER_LEN)  {
		cout
			<< "ERROR: trying to send a reliable packet of size " << bs.GetLength()
			<< " which is bigger than allowed size (" << (MAX_PACKET_SIZE - RELIABLE_HEADER_LEN)
			<< "), packet might not be sent at all!" << endl;
		Messages.push_back(bs); // Try to send it anyway, perhaps we're lucky...
		return;
	}

	// If no messages at all, add the first one
	if (Messages.size() == 0)  {
		Messages.push_back(bs);
		return;
	}

	// Some reliable messages already in queue, see if we should already split the packet
	if (bs.GetLength() + (Messages.rbegin()->GetLength()) > MAX_PACKET_SIZE)
		Messages.push_back(bs);
	else
		Messages.rbegin()->Append(&bs);
}

///////////////////
// Transmitt data, as well as handling reliable packets
void CChannel::Transmit( CBytestream *bs )
{
	CBytestream outpack;
	Uint32 SendReliable = 0;
	ulong r1,r2;

	// If the remote side dropped the last reliable packet, re-send it
	if(iIncomingAcknowledged > iLast_ReliableSequence && iIncoming_ReliableAcknowledged != iReliableSequence)  {
//		printf("Remote side dropped a reliable packet, resending...\n");
		SendReliable = 1;
	}

	// We send reliable message in these cases:
	// 1. The reliable buffer is empty, we copy the reliable message into it and send it
	// 2. We need to refresh ping
	if(Reliable.GetLength() == 0 && (Messages.size() > 0 || (tLX->fCurTime - fLastPingSent >= 1.0f && iPongSequence == -1))) {
		if (Messages.size() > 0)  {
			Reliable = *Messages.begin();
			Messages.erase(Messages.begin());
		}

		// We got a reliable packet to send
		SendReliable = 1;

		// XOR the reliable sequence
		iReliableSequence ^= 1;
	}

	// Create the reliable packet header
	r1 = iOutgoingSequence | (SendReliable << 31);
	r2 = iIncomingSequence | (iIncoming_ReliableSequence << 31);

	iOutgoingSequence++;

	outpack.writeInt(r1,4);
	outpack.writeInt(r2,4);

	// If were sending a reliable message, send it first
	if(SendReliable) {
		outpack.Append(&Reliable);
		iLast_ReliableSequence = iOutgoingSequence;

		// If we are sending a reliable message, remember this time and use it for ping calculations
		if (iPongSequence == -1)  {
			iPongSequence = iOutgoingSequence;
			fLastPingSent = GetMilliSeconds();
		}

	}

	// And add on the un reliable data if room in the packet struct
	if(bs) {
		if(outpack.GetLength() + bs->GetLength() < MAX_PACKET_SIZE) // Backward compatibility
			outpack.Append(bs);
	}

	// Send the packet
	SetRemoteNetAddr(Socket, RemoteAddr);
	outpack.Send(Socket);

	// Update statistics
	iOutgoingBytes += outpack.GetLength();
	iCurrentOutgoingBytes += outpack.GetLength();
	fLastSent = tLX->fCurTime;

	// Calculate the bytes per second
	if (tLX->fCurTime - fOutgoingClearTime >= 2.0f)  {
		fOutgoingRate = (float)iCurrentOutgoingBytes/(GetMilliSeconds() - fOutgoingClearTime);
		iCurrentOutgoingBytes = 0;
		fOutgoingClearTime = GetMilliSeconds();
	}
}

///////////////////
// Process channel (after receiving data)
bool CChannel::Process(CBytestream *bs)
{
	Uint32 Sequence, SequenceAck;
	Uint32 ReliableAck, ReliableMessage;
	int drop;

	// Start from the beginning of the packet
	bs->ResetPosToBegin();

	// Read the reliable packet header
	Sequence = bs->readInt(4);
	SequenceAck = bs->readInt(4);

	// Get the reliable bits
	ReliableMessage = Sequence >> 31;
	ReliableAck = SequenceAck >> 31;

	// Get rid of the reliable bits
	Sequence &= ~(1<<31);
	SequenceAck &= ~(1<<31);

	// Calculate the bytes per second
	iIncomingBytes += bs->GetRestLen();
	iCurrentIncomingBytes += bs->GetRestLen();
	if (tLX->fCurTime - fIncomingClearTime >= 2.0f)  {
		fIncomingRate = (float)iCurrentIncomingBytes/(GetMilliSeconds() - fIncomingClearTime);
		iCurrentIncomingBytes = 0;
		fIncomingClearTime = GetMilliSeconds();
	}

	// Get rid of the old packets
	// Small hack: there's a bug in old clients causing the first packet being ignored and resent later
	// It caused a delay when joining (especially on high-ping servers), this hack improves it
	if((Sequence <= iIncomingSequence) && (Sequence != 0 && iIncomingSequence != 0)) {
//		printf("Warning: Packet dropped\n");
//		bs->Dump();
		/*
		If we didn't ignore it here, we would become it
		again (the remote side will resend it because it thinks we've dropped
		the packet) and then parse it again => doubled text etc */
		// see GameServer::ReadPackets and CClient::ReadPackets
		// or perhaps it's ok to return true here but we should change the behaviour in *::ReadPackets
		return false;
	}

	// Check for dropped packets
	drop = Sequence - (iIncomingSequence+1);
	if(drop>0)
		// Update statistics
		iPacketsDropped++;

	// If the outgoing reliable message has been acknowledged, clear it for more reliable messages
	if(ReliableAck == iReliableSequence)
		Reliable.Clear();

	// Check if pong has been acknowledged
	if(SequenceAck >= (size_t)iPongSequence)  {
		iPongSequence = -1;  // Ready for new pinging
		iPing = MAX(0, (int)((tLX->fCurTime - fLastPingSent) * 1000));
	}

	// If this packet contained a reliable message, update the sequences
	iIncomingSequence = Sequence;
	iIncomingAcknowledged = SequenceAck;
	iIncoming_ReliableAcknowledged = ReliableAck;
	if(ReliableMessage)  {
		iIncoming_ReliableSequence ^= 1;
		bNewReliablePacket = true;
	} else
		bNewReliablePacket = false;

	// Update the statistics
	fLastPckRecvd = GetMilliSeconds();
	iPacketsGood++;

	return true;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windows.h>
#include <psapi.h>

#include "skia/ext/bitmap_platform_device_win.h"

#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "third_party/skia/include/core/SkUtils.h"

namespace skia {

namespace {

// Constrains position and size to fit within available_size. If |size| is -1,
// all the available_size is used. Returns false if the position is out of
// available_size.
bool Constrain(int available_size, int* position, int *size) {
  if (*size < -2)
    return false;

  if (*position < 0) {
    if (*size != -1)
      *size += *position;
    *position = 0;
  }
  if (*size == 0 || *position >= available_size)
    return false;

  if (*size > 0) {
    int overflow = (*position + *size) - available_size;
    if (overflow > 0) {
      *size -= overflow;
    }
  } else {
    // Fill up available size.
    *size = available_size - *position;
  }
  return true;
}

}  // namespace

class BitmapPlatformDevice::BitmapPlatformDeviceData : public SkRefCnt {
 public:
  explicit BitmapPlatformDeviceData(HBITMAP hbitmap);

  // Create/destroy hdc_, which is the memory DC for our bitmap data.
  HDC GetBitmapDC();
  void ReleaseBitmapDC();
  bool IsBitmapDCCreated() const;

  // Sets the transform and clip operations. This will not update the DC,
  // but will mark the config as dirty. The next call of LoadConfig will
  // pick up these changes.
  void SetMatrixClip(const SkMatrix& transform, const SkRegion& region);

  const SkMatrix& transform() const {
    return transform_;
  }

 protected:
  // Loads the current transform and clip into the DC. Can be called even when
  // the DC is NULL (will be a NOP).
  void LoadConfig();

  // Windows bitmap corresponding to our surface.
  HBITMAP hbitmap_;

  // Lazily-created DC used to draw into the bitmap, see getBitmapDC.
  HDC hdc_;

  // True when there is a transform or clip that has not been set to the DC.
  // The DC is retrieved for every text operation, and the transform and clip
  // do not change as much. We can save time by not loading the clip and
  // transform for every one.
  bool config_dirty_;

  // Translation assigned to the DC: we need to keep track of this separately
  // so it can be updated even if the DC isn't created yet.
  SkMatrix transform_;

  // The current clipping
  SkRegion clip_region_;

 private:
  virtual ~BitmapPlatformDeviceData();

  // Copy & assign are not supported.
  BitmapPlatformDeviceData(const BitmapPlatformDeviceData&);
  BitmapPlatformDeviceData& operator=(const BitmapPlatformDeviceData&);
};

BitmapPlatformDevice::BitmapPlatformDeviceData::BitmapPlatformDeviceData(
    HBITMAP hbitmap)
    : hbitmap_(hbitmap),
      hdc_(NULL),
      config_dirty_(true) {  // Want to load the config next time.
  // Initialize the clip region to the entire bitmap.
  BITMAP bitmap_data;
  if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) {
    SkIRect rect;
    rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight);
    clip_region_ = SkRegion(rect);
  }

  transform_.reset();
}

BitmapPlatformDevice::BitmapPlatformDeviceData::~BitmapPlatformDeviceData() {
  if (hdc_)
    ReleaseBitmapDC();

  // this will free the bitmap data as well as the bitmap handle
  DeleteObject(hbitmap_);
}

HDC BitmapPlatformDevice::BitmapPlatformDeviceData::GetBitmapDC() {
  if (!hdc_) {
    hdc_ = CreateCompatibleDC(NULL);
    InitializeDC(hdc_);
    HGDIOBJ old_bitmap = SelectObject(hdc_, hbitmap_);
    // When the memory DC is created, its display surface is exactly one
    // monochrome pixel wide and one monochrome pixel high. Since we select our
    // own bitmap, we must delete the previous one.
    DeleteObject(old_bitmap);
  }

  LoadConfig();
  return hdc_;
}

void BitmapPlatformDevice::BitmapPlatformDeviceData::ReleaseBitmapDC() {
  SkASSERT(hdc_);
  DeleteDC(hdc_);
  hdc_ = NULL;
}

bool BitmapPlatformDevice::BitmapPlatformDeviceData::IsBitmapDCCreated()
    const {
  return hdc_ != NULL;
}

void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip(
    const SkMatrix& transform,
    const SkRegion& region) {
  transform_ = transform;
  clip_region_ = region;
  config_dirty_ = true;
}

void BitmapPlatformDevice::BitmapPlatformDeviceData::LoadConfig() {
  if (!config_dirty_ || !hdc_)
    return;  // Nothing to do.
  config_dirty_ = false;

  // Transform.
  SkMatrix t(transform_);
  LoadTransformToDC(hdc_, t);
  LoadClippingRegionToDC(hdc_, clip_region_, t);
}

// We use this static factory function instead of the regular constructor so
// that we can create the pixel data before calling the constructor. This is
// required so that we can call the base class' constructor with the pixel
// data.
BitmapPlatformDevice* BitmapPlatformDevice::create(
    HDC screen_dc,
    int width,
    int height,
    bool is_opaque,
    HANDLE shared_section) {
  SkBitmap bitmap;

  // CreateDIBSection appears to get unhappy if we create an empty bitmap, so
  // just create a minimal bitmap
  if ((width == 0) || (height == 0)) {
    width = 1;
    height = 1;
  }

  BITMAPINFOHEADER hdr = {0};
  hdr.biSize = sizeof(BITMAPINFOHEADER);
  hdr.biWidth = width;
  hdr.biHeight = -height;  // minus means top-down bitmap
  hdr.biPlanes = 1;
  hdr.biBitCount = 32;
  hdr.biCompression = BI_RGB;  // no compression
  hdr.biSizeImage = 0;
  hdr.biXPelsPerMeter = 1;
  hdr.biYPelsPerMeter = 1;
  hdr.biClrUsed = 0;
  hdr.biClrImportant = 0;

  void* data = NULL;
  HBITMAP hbitmap = CreateDIBSection(screen_dc,
                                     reinterpret_cast<BITMAPINFO*>(&hdr), 0,
                                     &data,
                                     shared_section, 0);
  if (!hbitmap) {
    return NULL;
  }

  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
  bitmap.setPixels(data);
  bitmap.setIsOpaque(is_opaque);

  if (is_opaque) {
#ifndef NDEBUG
    // To aid in finding bugs, we set the background color to something
    // obviously wrong so it will be noticable when it is not cleared
    bitmap.eraseARGB(255, 0, 255, 128);  // bright bluish green
#endif
  } else {
    bitmap.eraseARGB(0, 0, 0, 0);
  }

  // The device object will take ownership of the HBITMAP. The initial refcount
  // of the data object will be 1, which is what the constructor expects.
  return new BitmapPlatformDevice(new BitmapPlatformDeviceData(hbitmap),
                                  bitmap);
}

// static
BitmapPlatformDevice* BitmapPlatformDevice::create(int width,
                                                   int height,
                                                   bool is_opaque,
                                                   HANDLE shared_section) {
  HDC screen_dc = GetDC(NULL);
  BitmapPlatformDevice* device = BitmapPlatformDevice::create(
      screen_dc, width, height, is_opaque, shared_section);
  ReleaseDC(NULL, screen_dc);
  return device;
}

// The device will own the HBITMAP, which corresponds to also owning the pixel
// data. Therefore, we do not transfer ownership to the SkDevice's bitmap.
BitmapPlatformDevice::BitmapPlatformDevice(
    BitmapPlatformDeviceData* data,
    const SkBitmap& bitmap)
    : PlatformDevice(bitmap),
      data_(data) {
  // The data object is already ref'ed for us by create().
}

// The copy constructor just adds another reference to the underlying data.
// We use a const cast since the default Skia definitions don't define the
// proper constedness that we expect (accessBitmap should really be const).
BitmapPlatformDevice::BitmapPlatformDevice(
    const BitmapPlatformDevice& other)
    : PlatformDevice(
          const_cast<BitmapPlatformDevice&>(other).accessBitmap(true)),
      data_(other.data_) {
  data_->ref();
}

BitmapPlatformDevice::~BitmapPlatformDevice() {
  data_->unref();
}

BitmapPlatformDevice& BitmapPlatformDevice::operator=(
    const BitmapPlatformDevice& other) {
  data_ = other.data_;
  data_->ref();
  return *this;
}

HDC BitmapPlatformDevice::getBitmapDC() {
  return data_->GetBitmapDC();
}

void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform,
                                         const SkRegion& region) {
  data_->SetMatrixClip(transform, region);
}

void BitmapPlatformDevice::drawToHDC(HDC dc, int x, int y,
                                     const RECT* src_rect) {
  bool created_dc = !data_->IsBitmapDCCreated();
  HDC source_dc = getBitmapDC();

  RECT temp_rect;
  if (!src_rect) {
    temp_rect.left = 0;
    temp_rect.right = width();
    temp_rect.top = 0;
    temp_rect.bottom = height();
    src_rect = &temp_rect;
  }

  int copy_width = src_rect->right - src_rect->left;
  int copy_height = src_rect->bottom - src_rect->top;

  // We need to reset the translation for our bitmap or (0,0) won't be in the
  // upper left anymore
  SkMatrix identity;
  identity.reset();

  LoadTransformToDC(source_dc, identity);
  if (isOpaque()) {
    BitBlt(dc,
           x,
           y,
           copy_width,
           copy_height,
           source_dc,
           src_rect->left,
           src_rect->top,
           SRCCOPY);
  } else {
    SkASSERT(copy_width != 0 && copy_height != 0);
    BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
    GdiAlphaBlend(dc,
                  x,
                  y,
                  copy_width,
                  copy_height,
                  source_dc,
                  src_rect->left,
                  src_rect->top,
                  copy_width,
                  copy_height,
                  blend_function);
  }
  LoadTransformToDC(source_dc, data_->transform());

  if (created_dc)
    data_->ReleaseBitmapDC();
}

void BitmapPlatformDevice::makeOpaque(int x, int y, int width, int height) {
  const SkBitmap& bitmap = accessBitmap(true);
  SkASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);

  // FIXME(brettw): This is kind of lame, we shouldn't be dealing with
  // transforms at this level. Probably there should be a PlatformCanvas
  // function that does the transform (using the actual transform not just the
  // translation) and calls us with the transformed rect.
  const SkMatrix& matrix = data_->transform();
  int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x;
  int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y;

  if (Constrain(bitmap.width(), &bitmap_start_x, &width) &&
      Constrain(bitmap.height(), &bitmap_start_y, &height)) {
    SkAutoLockPixels lock(bitmap);
    SkASSERT(bitmap.rowBytes() % sizeof(uint32_t) == 0u);
    size_t row_words = bitmap.rowBytes() / sizeof(uint32_t);
    // Set data to the first pixel to be modified.
    uint32_t* data = bitmap.getAddr32(0, 0) + (bitmap_start_y * row_words) +
                     bitmap_start_x;
    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++)
        data[j] |= (0xFF << SK_A32_SHIFT);
      data += row_words;
    }
  }
}

// Returns the color value at the specified location.
SkColor BitmapPlatformDevice::getColorAt(int x, int y) {
  const SkBitmap& bitmap = accessBitmap(false);
  SkAutoLockPixels lock(bitmap);
  uint32_t* data = bitmap.getAddr32(0, 0);
  return static_cast<SkColor>(data[x + y * width()]);
}

void BitmapPlatformDevice::onAccessBitmap(SkBitmap* bitmap) {
  // FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI
  // operation has occurred on our DC.
  if (data_->IsBitmapDCCreated())
    GdiFlush();
}

}  // namespace skia

<commit_msg>[Landing for Jonathon Dixon] Tiny code simplification/optimization: remove unecessay temporary copy of SkMatrix.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <windows.h>
#include <psapi.h>

#include "skia/ext/bitmap_platform_device_win.h"

#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "third_party/skia/include/core/SkUtils.h"

namespace skia {

namespace {

// Constrains position and size to fit within available_size. If |size| is -1,
// all the available_size is used. Returns false if the position is out of
// available_size.
bool Constrain(int available_size, int* position, int *size) {
  if (*size < -2)
    return false;

  if (*position < 0) {
    if (*size != -1)
      *size += *position;
    *position = 0;
  }
  if (*size == 0 || *position >= available_size)
    return false;

  if (*size > 0) {
    int overflow = (*position + *size) - available_size;
    if (overflow > 0) {
      *size -= overflow;
    }
  } else {
    // Fill up available size.
    *size = available_size - *position;
  }
  return true;
}

}  // namespace

class BitmapPlatformDevice::BitmapPlatformDeviceData : public SkRefCnt {
 public:
  explicit BitmapPlatformDeviceData(HBITMAP hbitmap);

  // Create/destroy hdc_, which is the memory DC for our bitmap data.
  HDC GetBitmapDC();
  void ReleaseBitmapDC();
  bool IsBitmapDCCreated() const;

  // Sets the transform and clip operations. This will not update the DC,
  // but will mark the config as dirty. The next call of LoadConfig will
  // pick up these changes.
  void SetMatrixClip(const SkMatrix& transform, const SkRegion& region);

  const SkMatrix& transform() const {
    return transform_;
  }

 protected:
  // Loads the current transform and clip into the DC. Can be called even when
  // the DC is NULL (will be a NOP).
  void LoadConfig();

  // Windows bitmap corresponding to our surface.
  HBITMAP hbitmap_;

  // Lazily-created DC used to draw into the bitmap, see getBitmapDC.
  HDC hdc_;

  // True when there is a transform or clip that has not been set to the DC.
  // The DC is retrieved for every text operation, and the transform and clip
  // do not change as much. We can save time by not loading the clip and
  // transform for every one.
  bool config_dirty_;

  // Translation assigned to the DC: we need to keep track of this separately
  // so it can be updated even if the DC isn't created yet.
  SkMatrix transform_;

  // The current clipping
  SkRegion clip_region_;

 private:
  virtual ~BitmapPlatformDeviceData();

  // Copy & assign are not supported.
  BitmapPlatformDeviceData(const BitmapPlatformDeviceData&);
  BitmapPlatformDeviceData& operator=(const BitmapPlatformDeviceData&);
};

BitmapPlatformDevice::BitmapPlatformDeviceData::BitmapPlatformDeviceData(
    HBITMAP hbitmap)
    : hbitmap_(hbitmap),
      hdc_(NULL),
      config_dirty_(true) {  // Want to load the config next time.
  // Initialize the clip region to the entire bitmap.
  BITMAP bitmap_data;
  if (GetObject(hbitmap_, sizeof(BITMAP), &bitmap_data)) {
    SkIRect rect;
    rect.set(0, 0, bitmap_data.bmWidth, bitmap_data.bmHeight);
    clip_region_ = SkRegion(rect);
  }

  transform_.reset();
}

BitmapPlatformDevice::BitmapPlatformDeviceData::~BitmapPlatformDeviceData() {
  if (hdc_)
    ReleaseBitmapDC();

  // this will free the bitmap data as well as the bitmap handle
  DeleteObject(hbitmap_);
}

HDC BitmapPlatformDevice::BitmapPlatformDeviceData::GetBitmapDC() {
  if (!hdc_) {
    hdc_ = CreateCompatibleDC(NULL);
    InitializeDC(hdc_);
    HGDIOBJ old_bitmap = SelectObject(hdc_, hbitmap_);
    // When the memory DC is created, its display surface is exactly one
    // monochrome pixel wide and one monochrome pixel high. Since we select our
    // own bitmap, we must delete the previous one.
    DeleteObject(old_bitmap);
  }

  LoadConfig();
  return hdc_;
}

void BitmapPlatformDevice::BitmapPlatformDeviceData::ReleaseBitmapDC() {
  SkASSERT(hdc_);
  DeleteDC(hdc_);
  hdc_ = NULL;
}

bool BitmapPlatformDevice::BitmapPlatformDeviceData::IsBitmapDCCreated()
    const {
  return hdc_ != NULL;
}

void BitmapPlatformDevice::BitmapPlatformDeviceData::SetMatrixClip(
    const SkMatrix& transform,
    const SkRegion& region) {
  transform_ = transform;
  clip_region_ = region;
  config_dirty_ = true;
}

void BitmapPlatformDevice::BitmapPlatformDeviceData::LoadConfig() {
  if (!config_dirty_ || !hdc_)
    return;  // Nothing to do.
  config_dirty_ = false;

  // Transform.
  LoadTransformToDC(hdc_, transform_);
  LoadClippingRegionToDC(hdc_, clip_region_, transform_);
}

// We use this static factory function instead of the regular constructor so
// that we can create the pixel data before calling the constructor. This is
// required so that we can call the base class' constructor with the pixel
// data.
BitmapPlatformDevice* BitmapPlatformDevice::create(
    HDC screen_dc,
    int width,
    int height,
    bool is_opaque,
    HANDLE shared_section) {
  SkBitmap bitmap;

  // CreateDIBSection appears to get unhappy if we create an empty bitmap, so
  // just create a minimal bitmap
  if ((width == 0) || (height == 0)) {
    width = 1;
    height = 1;
  }

  BITMAPINFOHEADER hdr = {0};
  hdr.biSize = sizeof(BITMAPINFOHEADER);
  hdr.biWidth = width;
  hdr.biHeight = -height;  // minus means top-down bitmap
  hdr.biPlanes = 1;
  hdr.biBitCount = 32;
  hdr.biCompression = BI_RGB;  // no compression
  hdr.biSizeImage = 0;
  hdr.biXPelsPerMeter = 1;
  hdr.biYPelsPerMeter = 1;
  hdr.biClrUsed = 0;
  hdr.biClrImportant = 0;

  void* data = NULL;
  HBITMAP hbitmap = CreateDIBSection(screen_dc,
                                     reinterpret_cast<BITMAPINFO*>(&hdr), 0,
                                     &data,
                                     shared_section, 0);
  if (!hbitmap) {
    return NULL;
  }

  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
  bitmap.setPixels(data);
  bitmap.setIsOpaque(is_opaque);

  if (is_opaque) {
#ifndef NDEBUG
    // To aid in finding bugs, we set the background color to something
    // obviously wrong so it will be noticable when it is not cleared
    bitmap.eraseARGB(255, 0, 255, 128);  // bright bluish green
#endif
  } else {
    bitmap.eraseARGB(0, 0, 0, 0);
  }

  // The device object will take ownership of the HBITMAP. The initial refcount
  // of the data object will be 1, which is what the constructor expects.
  return new BitmapPlatformDevice(new BitmapPlatformDeviceData(hbitmap),
                                  bitmap);
}

// static
BitmapPlatformDevice* BitmapPlatformDevice::create(int width,
                                                   int height,
                                                   bool is_opaque,
                                                   HANDLE shared_section) {
  HDC screen_dc = GetDC(NULL);
  BitmapPlatformDevice* device = BitmapPlatformDevice::create(
      screen_dc, width, height, is_opaque, shared_section);
  ReleaseDC(NULL, screen_dc);
  return device;
}

// The device will own the HBITMAP, which corresponds to also owning the pixel
// data. Therefore, we do not transfer ownership to the SkDevice's bitmap.
BitmapPlatformDevice::BitmapPlatformDevice(
    BitmapPlatformDeviceData* data,
    const SkBitmap& bitmap)
    : PlatformDevice(bitmap),
      data_(data) {
  // The data object is already ref'ed for us by create().
}

// The copy constructor just adds another reference to the underlying data.
// We use a const cast since the default Skia definitions don't define the
// proper constedness that we expect (accessBitmap should really be const).
BitmapPlatformDevice::BitmapPlatformDevice(
    const BitmapPlatformDevice& other)
    : PlatformDevice(
          const_cast<BitmapPlatformDevice&>(other).accessBitmap(true)),
      data_(other.data_) {
  data_->ref();
}

BitmapPlatformDevice::~BitmapPlatformDevice() {
  data_->unref();
}

BitmapPlatformDevice& BitmapPlatformDevice::operator=(
    const BitmapPlatformDevice& other) {
  data_ = other.data_;
  data_->ref();
  return *this;
}

HDC BitmapPlatformDevice::getBitmapDC() {
  return data_->GetBitmapDC();
}

void BitmapPlatformDevice::setMatrixClip(const SkMatrix& transform,
                                         const SkRegion& region) {
  data_->SetMatrixClip(transform, region);
}

void BitmapPlatformDevice::drawToHDC(HDC dc, int x, int y,
                                     const RECT* src_rect) {
  bool created_dc = !data_->IsBitmapDCCreated();
  HDC source_dc = getBitmapDC();

  RECT temp_rect;
  if (!src_rect) {
    temp_rect.left = 0;
    temp_rect.right = width();
    temp_rect.top = 0;
    temp_rect.bottom = height();
    src_rect = &temp_rect;
  }

  int copy_width = src_rect->right - src_rect->left;
  int copy_height = src_rect->bottom - src_rect->top;

  // We need to reset the translation for our bitmap or (0,0) won't be in the
  // upper left anymore
  SkMatrix identity;
  identity.reset();

  LoadTransformToDC(source_dc, identity);
  if (isOpaque()) {
    BitBlt(dc,
           x,
           y,
           copy_width,
           copy_height,
           source_dc,
           src_rect->left,
           src_rect->top,
           SRCCOPY);
  } else {
    SkASSERT(copy_width != 0 && copy_height != 0);
    BLENDFUNCTION blend_function = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
    GdiAlphaBlend(dc,
                  x,
                  y,
                  copy_width,
                  copy_height,
                  source_dc,
                  src_rect->left,
                  src_rect->top,
                  copy_width,
                  copy_height,
                  blend_function);
  }
  LoadTransformToDC(source_dc, data_->transform());

  if (created_dc)
    data_->ReleaseBitmapDC();
}

void BitmapPlatformDevice::makeOpaque(int x, int y, int width, int height) {
  const SkBitmap& bitmap = accessBitmap(true);
  SkASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);

  // FIXME(brettw): This is kind of lame, we shouldn't be dealing with
  // transforms at this level. Probably there should be a PlatformCanvas
  // function that does the transform (using the actual transform not just the
  // translation) and calls us with the transformed rect.
  const SkMatrix& matrix = data_->transform();
  int bitmap_start_x = SkScalarRound(matrix.getTranslateX()) + x;
  int bitmap_start_y = SkScalarRound(matrix.getTranslateY()) + y;

  if (Constrain(bitmap.width(), &bitmap_start_x, &width) &&
      Constrain(bitmap.height(), &bitmap_start_y, &height)) {
    SkAutoLockPixels lock(bitmap);
    SkASSERT(bitmap.rowBytes() % sizeof(uint32_t) == 0u);
    size_t row_words = bitmap.rowBytes() / sizeof(uint32_t);
    // Set data to the first pixel to be modified.
    uint32_t* data = bitmap.getAddr32(0, 0) + (bitmap_start_y * row_words) +
                     bitmap_start_x;
    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++)
        data[j] |= (0xFF << SK_A32_SHIFT);
      data += row_words;
    }
  }
}

// Returns the color value at the specified location.
SkColor BitmapPlatformDevice::getColorAt(int x, int y) {
  const SkBitmap& bitmap = accessBitmap(false);
  SkAutoLockPixels lock(bitmap);
  uint32_t* data = bitmap.getAddr32(0, 0);
  return static_cast<SkColor>(data[x + y * width()]);
}

void BitmapPlatformDevice::onAccessBitmap(SkBitmap* bitmap) {
  // FIXME(brettw) OPTIMIZATION: We should only flush if we know a GDI
  // operation has occurred on our DC.
  if (data_->IsBitmapDCCreated())
    GdiFlush();
}

}  // namespace skia

<|endoftext|>


<commit_before>#pragma once

#include "blitz_typedefs.hpp"
#include "constants.hpp"
#include "error.hpp"
#include "global_config.hpp"

namespace mocc {

    typedef std::array<int, 3> BC_Size_t;
    typedef std::array<Boundary, 6> BC_Type_t;

    /**
     * This defines a general boundary condition container, which can store an
     * angular flux condition as a 1-dimensional collection of values for
     * each dimension-normal, angle, and energy. It is the responsibility of the
     * sweeper itself to determine what the indices of the actual conditions
     * mean.
     *
     * This class shall make one important guarantee; that all faces of the BC
     * in an angle/group are stored consecutively. This potentially allows
     * client code to eschew the concept of surface normals entirely. See \ref
     * moc::MoCSweeper for an example of this.
     */
    class BoundaryCondition {
    public:
        /**
         * \brief Construct a simple boundary condition, where there are the
         * same number of conditions per face/angle (Sn case).
         *
         * \param n_group the number of groups
         * \param angquad the \ref AngularQuadrature to use for reflections and
         * such
         * \param bc the \ref Boundary condition to enforce at each domain
         * boundary
         * \param n_bc the number of conditions to store for each direction
         * normal.
         *
         * To cut down on code duplication, just expand the scalar \p n_bc into
         * a vector and call the general case (below).
         */
        BoundaryCondition( int n_group, const AngularQuadrature &angquad,
                BC_Type_t bc, BC_Size_t n_bc ):
            BoundaryCondition( n_group,
                               angquad,
                               bc,
                               std::vector<BC_Size_t>(angquad.ndir(), n_bc)
                             )
        {
            return;
        }

        /**
         * \brief Construct a more complicated boundary condition, where each
         * angle can have a different number of conditions (MoC case).
         *
         * \param n_group the number of groups
         * \param angquad the \ref AngularQuadrature to use for reflections and
         * such
         * \param bc the \ref Boundary condition to enforce at each domain
         * boundary
         * \param n_bc a vector containing the number of BCs needed for each
         * angle.
         */
        BoundaryCondition( int n_group, const AngularQuadrature &angquad,
                BC_Type_t bc, std::vector< BC_Size_t > n_bc ):
            n_group_(n_group),
            n_angle_(n_bc.size()),
            bc_(bc),
            size_(n_bc),
            ang_quad_(angquad)
        {
            assert( (angquad.ndir()   == (int)n_bc.size()) ||
                    (angquad.ndir()/2 == (int)n_bc.size()) );

            int n_angle = n_bc.size();

            bc_per_group_ = 0;
            for( auto n: n_bc ) {
                bc_per_group_ += n[0] + n[1] + n[2];
            }

            size_t total_size = bc_per_group_*n_group;
            data_.resize(total_size);
            offset_.resize(n_angle, 3);
            assert(offset_( 0, blitz::Range::all() ).isStorageContiguous());

            int offset = 0;
            int iang = 0;
            for( auto n_ang: n_bc ) {
                int iface = 0;
                for( auto n: n_ang ) {
                    offset_(iang, iface) = offset;
                    offset += n;
                    iface++;
                }
                iang++;
            }
            return;
        }

        /**
         * \brief Return the total number of boundary condition points.
         */
        int size() const {
            return data_.size();
        }

        /**
         * \brief Initialize all BC points with a given value
         */
        void initialize_scalar( real_t val ) {
            data_ = val;
        }

        /**
         * \brief Initialize the boundary conditions with an energy spectrum.
         */
        void initialize_spectrum( const ArrayB1 &spectrum ) {
            assert( (int)spectrum.size() == n_group_ );
            int it = 0;
            for( int ig=0; ig<n_group_; ig++ ) {
                real_t val = spectrum(ig);
                data_( blitz::Range(it, it+bc_per_group_-1) ) = val;
                it += bc_per_group_;
            }
            return;
        }

        /**
         * \brief Return a const pointer to the beginning of a boundary
         * condition face
         */
        const real_t* get_face( int group, int angle, Normal norm ) const {
            assert(angle < n_angle_);
            assert(group < n_group_ );
            int off = bc_per_group_*group + offset_(angle, (int)norm);
            return &data_(off);
        }

        /**
         * \brief Return a pointer to the beginning of a boundary condition face
         */
        real_t* get_face( int group, int angle, Normal norm ) {
            assert(angle < n_angle_);
            assert(group < n_group_ );
            int off = bc_per_group_*group + offset_(angle, (int)norm);
            return &data_(off);
        }

        /**
         * \brief Return a pointer to the beginning of the boundary values for
         * the given group and angle
         */
        const real_t* get_boundary( int group, int angle ) const {
            assert(angle < n_angle_);
            assert(group < n_group_ );
            int off = bc_per_group_*group + offset_(angle, 0);
            return &data_(off);
        }

        /**
         * \brief Return a pointer to the beginning of the boundary values for
         * the given group and angle
         */
        real_t* get_boundary( int group, int angle ) {
            assert(angle < n_angle_);
            assert(group < n_group_ );
            int off = bc_per_group_*group + offset_(angle, 0);
            return &data_(off);
        }

        /**
         * \brief Update the boundary condition for all angles for a single
         * group using a passed-in "outgoing" condition.
         *
         * \param group the energy group to update
         * \param out the "outgoing" angular flux boundary condition to use in
         * the update. It should only have one group of storage
         *
         * This would be used for a Jacobi-style iteration on the boundary
         * source.
         */
        void update( int group, const BoundaryCondition &out ) {
            assert( out.n_group_ == 1 );

            for( int iang=0; iang<n_angle_; iang++ ) {
                this->update( group, iang, out );
            }
            return;
        }

        /**
         * \brief Update the boundary condition from a single outgoing angle for
         * a single group using a passed-in "outgoing" condition.
         *
         * \param group the energy group to treat
         * \param angle the angle index of the outgoing angle. See below.
         * \param out a single-group \ref BoundaryCondition object storing the
         * outgoing boundary values to use.
         *
         * This would be used for a Gauss-Seidel-style iteration on the boundary
         * source.
         *
         * The passed angle indicates the angle of the outgoing angle. Depending
         * on the various domain boundary conditions, corresponding boundary
         * values may be updated on \c this
         */
        void update( int group, int angle, const BoundaryCondition &out ) {
            assert( angle < ang_quad_.ndir()/2 );
            int group_offset = bc_per_group_*group;

            for( Normal n: AllNormals ) {
                int size = size_[angle][(int)n];
                int iang_in = ang_quad_.reflect(angle, n);
                if( size == 0 ) {
                    break;
                }
                assert( size == out.size_[iang_in][(int)n]);
                assert( iang_in < n_angle_ );
                const auto &angle_in = ang_quad_[iang_in];
                int offset_in = group_offset + offset_(iang_in, (int)n);
                int offset_out = out.offset_(angle, (int)n);;

                switch( bc_[(int)(angle_in.upwind_surface(n))] ) {
                case Boundary::VACUUM:
                    data_(blitz::Range(offset_in, offset_in+size-1)) = 0.0;
                    break;

                case Boundary::REFLECT:
                    data_(blitz::Range(offset_in, offset_in+size-1)) =
                        out.data_(blitz::Range(offset_out, offset_out+size-1));
                    break;

                default:
                    throw EXCEPT("Unsupported boundary condition type");
                }
            }
            return;
        }

    private:
        // Number of energy groups
        int n_group_;

        // Number of angles to track
        int n_angle_;

        // Boundary conditions
        std::array<Boundary, 6> bc_;

        std::vector<BC_Size_t> size_;

        // Angular quadratrue used to do angle index reflections
        const AngularQuadrature &ang_quad_;

        // Number of BCs per energy groups. Essentially the sum of the BCs on
        // all faces for all angles
        int bc_per_group_;

        // Large vector containing all of the boundary conditions for all
        // angles, groups and faces
        ArrayB1 data_;

        // An array of index offsets to get to an angle/face. Needs to be
        // incremented by bc_per_group_*group to yield final starting index of a
        // face of BCs
        blitz::Array<int, 2> offset_;

    };
}
<commit_msg>Add copy_face method to BoundaryCondition<commit_after>#pragma once

#include "blitz_typedefs.hpp"
#include "constants.hpp"
#include "error.hpp"
#include "global_config.hpp"

namespace mocc {

    typedef std::array<int, 3> BC_Size_t;
    typedef std::array<Boundary, 6> BC_Type_t;

    /**
     * This defines a general boundary condition container, which can store an
     * angular flux condition as a 1-dimensional collection of values for
     * each dimension-normal, angle, and energy. It is the responsibility of the
     * sweeper itself to determine what the indices of the actual conditions
     * mean.
     *
     * This class shall make one important guarantee; that all faces of the BC
     * in an angle/group are stored consecutively. This potentially allows
     * client code to eschew the concept of surface normals entirely. See \ref
     * moc::MoCSweeper for an example of this.
     */
    class BoundaryCondition {
    public:
        /**
         * \brief Construct a simple boundary condition, where there are the
         * same number of conditions per face/angle (Sn case).
         *
         * \param n_group the number of groups
         * \param angquad the \ref AngularQuadrature to use for reflections and
         * such
         * \param bc the \ref Boundary condition to enforce at each domain
         * boundary
         * \param n_bc the number of conditions to store for each direction
         * normal.
         *
         * To cut down on code duplication, just expand the scalar \p n_bc into
         * a vector and call the general case (below).
         */
        BoundaryCondition( int n_group, const AngularQuadrature &angquad,
                BC_Type_t bc, BC_Size_t n_bc ):
            BoundaryCondition( n_group,
                               angquad,
                               bc,
                               std::vector<BC_Size_t>(angquad.ndir(), n_bc)
                             )
        {
            return;
        }

        /**
         * \brief Construct a more complicated boundary condition, where each
         * angle can have a different number of conditions (MoC case).
         *
         * \param n_group the number of groups
         * \param angquad the \ref AngularQuadrature to use for reflections and
         * such
         * \param bc the \ref Boundary condition to enforce at each domain
         * boundary
         * \param n_bc a vector containing the number of BCs needed for each
         * angle.
         */
        BoundaryCondition( int n_group, const AngularQuadrature &angquad,
                BC_Type_t bc, std::vector< BC_Size_t > n_bc ):
            n_group_(n_group),
            n_angle_(n_bc.size()),
            bc_(bc),
            size_(n_bc),
            ang_quad_(angquad)
        {
            assert( (angquad.ndir()   == (int)n_bc.size()) ||
                    (angquad.ndir()/2 == (int)n_bc.size()) );

            int n_angle = n_bc.size();

            bc_per_group_ = 0;
            for( auto n: n_bc ) {
                bc_per_group_ += n[0] + n[1] + n[2];
            }

            size_t total_size = bc_per_group_*n_group;
            data_.resize(total_size);
            offset_.resize(n_angle, 3);
            assert(offset_( 0, blitz::Range::all() ).isStorageContiguous());

            int offset = 0;
            int iang = 0;
            for( auto n_ang: n_bc ) {
                int iface = 0;
                for( auto n: n_ang ) {
                    offset_(iang, iface) = offset;
                    offset += n;
                    iface++;
                }
                iang++;
            }
            return;
        }

        /**
         * \brief Return the total number of boundary condition points.
         */
        int size() const {
            return data_.size();
        }

        /**
         * \brief Initialize all BC points with a given value
         */
        void initialize_scalar( real_t val ) {
            data_ = val;
        }

        /**
         * \brief Initialize the boundary conditions with an energy spectrum.
         */
        void initialize_spectrum( const ArrayB1 &spectrum ) {
            assert( (int)spectrum.size() == n_group_ );
            int it = 0;
            for( int ig=0; ig<n_group_; ig++ ) {
                real_t val = spectrum(ig);
                data_( blitz::Range(it, it+bc_per_group_-1) ) = val;
                it += bc_per_group_;
            }
            return;
        }

        /**
         * \brief Return a const pointer to the beginning of a boundary
         * condition face
         */
        const real_t* get_face( int group, int angle, Normal norm ) const {
            assert(angle < n_angle_);
            assert(group < n_group_ );
            int off = bc_per_group_*group + offset_(angle, (int)norm);
            return &data_(off);
        }

        /**
         * \brief Return a pointer to the beginning of a boundary condition face
         */
        real_t* get_face( int group, int angle, Normal norm ) {
            assert(angle < n_angle_);
            assert(group < n_group_ );
            int off = bc_per_group_*group + offset_(angle, (int)norm);
            return &data_(off);
        }

        /**
         * \breif Copy boundary values to external array
         */
        void copy_face( int group, int angle, Normal norm, real_t *out ) {
            int n = size_[angle][(int)norm];
            const real_t *face = this->get_face( group, angle, norm );
            std::copy( face, face+n, out );
        }

        /**
         * \brief Return a pointer to the beginning of the boundary values for
         * the given group and angle
         */
        const real_t* get_boundary( int group, int angle ) const {
            assert(angle < n_angle_);
            assert(group < n_group_ );
            int off = bc_per_group_*group + offset_(angle, 0);
            return &data_(off);
        }

        /**
         * \brief Return a pointer to the beginning of the boundary values for
         * the given group and angle
         */
        real_t* get_boundary( int group, int angle ) {
            assert(angle < n_angle_);
            assert(group < n_group_ );
            int off = bc_per_group_*group + offset_(angle, 0);
            return &data_(off);
        }

        /**
         * \brief Update the boundary condition for all angles for a single
         * group using a passed-in "outgoing" condition.
         *
         * \param group the energy group to update
         * \param out the "outgoing" angular flux boundary condition to use in
         * the update. It should only have one group of storage
         *
         * This would be used for a Jacobi-style iteration on the boundary
         * source.
         */
        void update( int group, const BoundaryCondition &out ) {
            assert( out.n_group_ == 1 );

            for( int iang=0; iang<n_angle_; iang++ ) {
                this->update( group, iang, out );
            }
            return;
        }

        /**
         * \brief Update the boundary condition from a single outgoing angle for
         * a single group using a passed-in "outgoing" condition.
         *
         * \param group the energy group to treat
         * \param angle the angle index of the outgoing angle. See below.
         * \param out a single-group \ref BoundaryCondition object storing the
         * outgoing boundary values to use.
         *
         * This would be used for a Gauss-Seidel-style iteration on the boundary
         * source.
         *
         * The passed angle indicates the angle of the outgoing angle. Depending
         * on the various domain boundary conditions, corresponding boundary
         * values may be updated on \c this
         */
        void update( int group, int angle, const BoundaryCondition &out ) {
            assert( angle < ang_quad_.ndir()/2 );
            int group_offset = bc_per_group_*group;

            for( Normal n: AllNormals ) {
                int size = size_[angle][(int)n];
                int iang_in = ang_quad_.reflect(angle, n);
                if( size == 0 ) {
                    break;
                }
                assert( size == out.size_[iang_in][(int)n]);
                assert( iang_in < n_angle_ );
                const auto &angle_in = ang_quad_[iang_in];
                int offset_in = group_offset + offset_(iang_in, (int)n);
                int offset_out = out.offset_(angle, (int)n);;

                switch( bc_[(int)(angle_in.upwind_surface(n))] ) {
                case Boundary::VACUUM:
                    data_(blitz::Range(offset_in, offset_in+size-1)) = 0.0;
                    break;

                case Boundary::REFLECT:
                    data_(blitz::Range(offset_in, offset_in+size-1)) =
                        out.data_(blitz::Range(offset_out, offset_out+size-1));
                    break;

                default:
                    throw EXCEPT("Unsupported boundary condition type");
                }
            }
            return;
        }

    private:
        // Number of energy groups
        int n_group_;

        // Number of angles to track
        int n_angle_;

        // Boundary conditions
        std::array<Boundary, 6> bc_;

        std::vector<BC_Size_t> size_;

        // Angular quadratrue used to do angle index reflections
        const AngularQuadrature &ang_quad_;

        // Number of BCs per energy groups. Essentially the sum of the BCs on
        // all faces for all angles
        int bc_per_group_;

        // Large vector containing all of the boundary conditions for all
        // angles, groups and faces
        ArrayB1 data_;

        // An array of index offsets to get to an angle/face. Needs to be
        // incremented by bc_per_group_*group to yield final starting index of a
        // face of BCs
        blitz::Array<int, 2> offset_;

    };
}
<|endoftext|>


<commit_before>int ans = N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) );
<commit_msg>Outra forma<commit_after>int ans = N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) );

// Outra forma
int xorUpToK(int k) {
	switch (k % 4) {
		case 0: return k;
		case 1: return 1;
		case 2: return k + 1;
		case 3: return 0;
	}
}
<|endoftext|>


<commit_before>#include "object.hpp"
#include "glyph.hpp"
#include "species.hpp"
#include "object_struct.hpp"
#include "render_templates.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <iostream> // std::cout, std::cin, std::cerr

namespace ontology
{
    void Object::bind_to_parent()
    {
        // get `childID` from `Species` or `Glyph` and set pointer to this `Object`.

        if (this->is_character)
        {
            ontology::Text3D* parent_pointer;
            parent_pointer = this->text3D_parent_pointer;
            // for ontological hierarchy (rendering hierarchy does not use `childID`).
            // get `childID` from `Glyph` and set pointer to this `Object`.
            hierarchy::bind_child_to_parent<ontology::Object*>(this, parent_pointer->object_pointer_vector, parent_pointer->free_objectID_queue, &parent_pointer->number_of_objects);
        }
        else
        {
            ontology::Species* parent_pointer;
            parent_pointer = this->species_parent_pointer;
            // for ontological hierarchy (rendering hierarchy does not use `childID`).
            // get `childID` from `Species` and set pointer to this `Object`.
            hierarchy::bind_child_to_parent<ontology::Object*>(this, parent_pointer->object_pointer_vector, parent_pointer->free_objectID_queue, &parent_pointer->number_of_objects);
        }
    }

    Object::Object(const ObjectStruct object_struct)
    {
        // constructor.
        this->coordinate_vector     = object_struct.coordinate_vector;
        this->original_scale_vector = object_struct.original_scale_vector;
        this->rotate_angle          = object_struct.rotate_angle;
        this->rotate_vector         = object_struct.rotate_vector;
        this->translate_vector      = object_struct.translate_vector;
        this->has_entered           = false;

        // enable rendering of a recently entered Object.
        // TODO: enable entering without enabling rendering.
        this->should_ylikuutio_render_this_object = true;

        this->is_character          = object_struct.is_character;

        if (this->is_character)
        {
            this->species_parent_pointer = nullptr;
            this->glyph_parent_pointer   = object_struct.glyph_parent_pointer;
            this->text3D_parent_pointer  = object_struct.text3D_parent_pointer;
            this->universe_pointer       = this->text3D_parent_pointer->universe_pointer;
        }
        else
        {
            this->species_parent_pointer = object_struct.species_parent_pointer;
            this->universe_pointer       = this->species_parent_pointer->universe_pointer;
            this->glyph_parent_pointer   = nullptr;
            this->text3D_parent_pointer  = nullptr;
        }

        // get `childID` from `Species` or `Glyph` and set pointer to this `Object`.
        this->bind_to_parent();
        this->type = "ontology::Object*";
    }

    Object::~Object()
    {
        // destructor.

        // set pointer to this object to nullptr.
        if (this->is_character)
        {
            std::string unicode_string = this->glyph_parent_pointer->unicode_char_pointer;
            std::cout << "Object with childID " << std::dec << this->childID << " (Unicode: \"" << unicode_string << "\") will be destroyed.\n";
            this->text3D_parent_pointer->set_object_pointer(this->childID, nullptr);
        }
        else
        {
            std::cout << "Object with childID " << std::dec << this->childID << " will be destroyed.\n";
            this->species_parent_pointer->set_object_pointer(this->childID, nullptr);
        }
    }

    void Object::act()
    {
        // TODO: act according to this game/simulation object's programming.
    }

    void Object::render()
    {
        // render this `Object`.

        if (this->should_ylikuutio_render_this_object)
        {
            this->prerender();

            ontology::Shader* shader_pointer;

            if (this->is_character)
            {
                shader_pointer = this->glyph_parent_pointer->parent_pointer->parent_pointer->parent_pointer;
                ontology::render_this_object<ontology::Glyph*>(this, shader_pointer);
            }
            else
            {
                shader_pointer = this->species_parent_pointer->parent_pointer->parent_pointer;
                ontology::render_this_object<ontology::Species*>(this, shader_pointer);
            }

            this->postrender();
        }
    }

    int32_t Object::get_number_of_children()
    {
        return 0;
    }

    int32_t Object::get_number_of_descendants()
    {
        return 0;
    }

    void Object::bind_to_new_parent(void* const new_parent_pointer)
    {
        // this method sets pointer to this `Object` to nullptr, sets `parent_pointer` according to the input,
        // and requests a new `childID` from the new `Species` or from the new `Glyph`.

        if (this->is_character)
        {
            ontology::Glyph* parent_pointer;
            parent_pointer = this->glyph_parent_pointer;
            // set pointer to this child to nullptr in the old parent.
            ontology::Object* dummy_child_pointer = nullptr;
            hierarchy::set_child_pointer(this->childID, dummy_child_pointer, glyph_parent_pointer->object_pointer_vector, glyph_parent_pointer->free_objectID_queue, &glyph_parent_pointer->number_of_objects);
            // set the new parent pointer.
            this->glyph_parent_pointer = static_cast<ontology::Glyph*>(new_parent_pointer);
            // bind to the new parent.
            this->bind_to_parent();
        }
        else
        {
            ontology::Species* parent_pointer;
            parent_pointer = this->species_parent_pointer;
            // set pointer to this child to nullptr in the old parent.
            ontology::Object* dummy_child_pointer = nullptr;
            hierarchy::set_child_pointer(this->childID, dummy_child_pointer, species_parent_pointer->object_pointer_vector, species_parent_pointer->free_objectID_queue, &species_parent_pointer->number_of_objects);
            // set the new parent pointer.
            this->species_parent_pointer = static_cast<ontology::Species*>(new_parent_pointer);
            // bind to the new parent.
            this->bind_to_parent();
        }
    }

    void Object::set_name(const std::string& name)
    {
        ontology::set_name(name, this);
    }

    // Public callbacks (to be called from AI scripts written in Chibi-Scheme).

    void Object::set_dest(ontology::Object* const object, const float x, const float y, const float z)
    {
        // Set target towards which to move.
        object->dest_vector = glm::vec3(x, y, z);
    }

    float Object::get_x(const ontology::Object* const object)
    {
        // Get x coordinate of `object`.
        return object->coordinate_vector.x;
    }

    float Object::get_y(const ontology::Object* const object)
    {
        // Get y coordinate of `object`.
        return object->coordinate_vector.x;
    }

    float Object::get_z(const ontology::Object* const object)
    {
        // Get z coordinate of `object`.
        return object->coordinate_vector.x;
    }

    float Object::get_dest_x(const ontology::Object* const object)
    {
        // Get x destination coordinate of `object`.
        return object->dest_vector.x;
    }

    float Object::get_dest_y(const ontology::Object* const object)
    {
        // Get y destination coordinate of `object`.
        return object->dest_vector.x;
    }

    float Object::get_dest_z(const ontology::Object* const object)
    {
        // Get z destination coordinate of `object`.
        return object->dest_vector.x;
    }

    // Public callbacks end here.
}
<commit_msg>`Object::Object`: reordering code lines.<commit_after>#include "object.hpp"
#include "glyph.hpp"
#include "species.hpp"
#include "object_struct.hpp"
#include "render_templates.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <iostream> // std::cout, std::cin, std::cerr

namespace ontology
{
    void Object::bind_to_parent()
    {
        // get `childID` from `Species` or `Glyph` and set pointer to this `Object`.

        if (this->is_character)
        {
            ontology::Text3D* parent_pointer;
            parent_pointer = this->text3D_parent_pointer;
            // for ontological hierarchy (rendering hierarchy does not use `childID`).
            // get `childID` from `Glyph` and set pointer to this `Object`.
            hierarchy::bind_child_to_parent<ontology::Object*>(this, parent_pointer->object_pointer_vector, parent_pointer->free_objectID_queue, &parent_pointer->number_of_objects);
        }
        else
        {
            ontology::Species* parent_pointer;
            parent_pointer = this->species_parent_pointer;
            // for ontological hierarchy (rendering hierarchy does not use `childID`).
            // get `childID` from `Species` and set pointer to this `Object`.
            hierarchy::bind_child_to_parent<ontology::Object*>(this, parent_pointer->object_pointer_vector, parent_pointer->free_objectID_queue, &parent_pointer->number_of_objects);
        }
    }

    Object::Object(const ObjectStruct object_struct)
    {
        // constructor.
        this->coordinate_vector     = object_struct.coordinate_vector;
        this->original_scale_vector = object_struct.original_scale_vector;
        this->rotate_angle          = object_struct.rotate_angle;
        this->rotate_vector         = object_struct.rotate_vector;
        this->translate_vector      = object_struct.translate_vector;
        this->has_entered           = false;

        // enable rendering of a recently entered Object.
        // TODO: enable entering without enabling rendering.
        this->should_ylikuutio_render_this_object = true;

        this->is_character          = object_struct.is_character;

        if (this->is_character)
        {
            this->glyph_parent_pointer   = object_struct.glyph_parent_pointer;
            this->text3D_parent_pointer  = object_struct.text3D_parent_pointer;
            this->universe_pointer       = this->text3D_parent_pointer->universe_pointer;
            this->species_parent_pointer = nullptr;
        }
        else
        {
            this->species_parent_pointer = object_struct.species_parent_pointer;
            this->universe_pointer       = this->species_parent_pointer->universe_pointer;
            this->glyph_parent_pointer   = nullptr;
            this->text3D_parent_pointer  = nullptr;
        }

        // get `childID` from `Species` or `Glyph` and set pointer to this `Object`.
        this->bind_to_parent();
        this->type = "ontology::Object*";
    }

    Object::~Object()
    {
        // destructor.

        // set pointer to this object to nullptr.
        if (this->is_character)
        {
            std::string unicode_string = this->glyph_parent_pointer->unicode_char_pointer;
            std::cout << "Object with childID " << std::dec << this->childID << " (Unicode: \"" << unicode_string << "\") will be destroyed.\n";
            this->text3D_parent_pointer->set_object_pointer(this->childID, nullptr);
        }
        else
        {
            std::cout << "Object with childID " << std::dec << this->childID << " will be destroyed.\n";
            this->species_parent_pointer->set_object_pointer(this->childID, nullptr);
        }
    }

    void Object::act()
    {
        // TODO: act according to this game/simulation object's programming.
    }

    void Object::render()
    {
        // render this `Object`.

        if (this->should_ylikuutio_render_this_object)
        {
            this->prerender();

            ontology::Shader* shader_pointer;

            if (this->is_character)
            {
                shader_pointer = this->glyph_parent_pointer->parent_pointer->parent_pointer->parent_pointer;
                ontology::render_this_object<ontology::Glyph*>(this, shader_pointer);
            }
            else
            {
                shader_pointer = this->species_parent_pointer->parent_pointer->parent_pointer;
                ontology::render_this_object<ontology::Species*>(this, shader_pointer);
            }

            this->postrender();
        }
    }

    int32_t Object::get_number_of_children()
    {
        return 0;
    }

    int32_t Object::get_number_of_descendants()
    {
        return 0;
    }

    void Object::bind_to_new_parent(void* const new_parent_pointer)
    {
        // this method sets pointer to this `Object` to nullptr, sets `parent_pointer` according to the input,
        // and requests a new `childID` from the new `Species` or from the new `Glyph`.

        if (this->is_character)
        {
            ontology::Glyph* parent_pointer;
            parent_pointer = this->glyph_parent_pointer;
            // set pointer to this child to nullptr in the old parent.
            ontology::Object* dummy_child_pointer = nullptr;
            hierarchy::set_child_pointer(this->childID, dummy_child_pointer, glyph_parent_pointer->object_pointer_vector, glyph_parent_pointer->free_objectID_queue, &glyph_parent_pointer->number_of_objects);
            // set the new parent pointer.
            this->glyph_parent_pointer = static_cast<ontology::Glyph*>(new_parent_pointer);
            // bind to the new parent.
            this->bind_to_parent();
        }
        else
        {
            ontology::Species* parent_pointer;
            parent_pointer = this->species_parent_pointer;
            // set pointer to this child to nullptr in the old parent.
            ontology::Object* dummy_child_pointer = nullptr;
            hierarchy::set_child_pointer(this->childID, dummy_child_pointer, species_parent_pointer->object_pointer_vector, species_parent_pointer->free_objectID_queue, &species_parent_pointer->number_of_objects);
            // set the new parent pointer.
            this->species_parent_pointer = static_cast<ontology::Species*>(new_parent_pointer);
            // bind to the new parent.
            this->bind_to_parent();
        }
    }

    void Object::set_name(const std::string& name)
    {
        ontology::set_name(name, this);
    }

    // Public callbacks (to be called from AI scripts written in Chibi-Scheme).

    void Object::set_dest(ontology::Object* const object, const float x, const float y, const float z)
    {
        // Set target towards which to move.
        object->dest_vector = glm::vec3(x, y, z);
    }

    float Object::get_x(const ontology::Object* const object)
    {
        // Get x coordinate of `object`.
        return object->coordinate_vector.x;
    }

    float Object::get_y(const ontology::Object* const object)
    {
        // Get y coordinate of `object`.
        return object->coordinate_vector.x;
    }

    float Object::get_z(const ontology::Object* const object)
    {
        // Get z coordinate of `object`.
        return object->coordinate_vector.x;
    }

    float Object::get_dest_x(const ontology::Object* const object)
    {
        // Get x destination coordinate of `object`.
        return object->dest_vector.x;
    }

    float Object::get_dest_y(const ontology::Object* const object)
    {
        // Get y destination coordinate of `object`.
        return object->dest_vector.x;
    }

    float Object::get_dest_z(const ontology::Object* const object)
    {
        // Get z destination coordinate of `object`.
        return object->dest_vector.x;
    }

    // Public callbacks end here.
}
<|endoftext|>