<commit_before>#include "markov.h"
#include "random.h"
#include "rodrigues.h"
#include "compiler.h"

// The procedure below gives rise to roughly the following relative polyhedron abundancies.

// 8.10 % tetrahedron
// 8.66 % octahedron
// 4.68 % cube
// 7.70 % icosahedron
// 4.62 % dodecahedron
// 5.81 % truncated tetrahedron
// 9.55 % truncated octahedron
// 3.48 % truncated cube
// 3.46 % truncated icosahedron
// 3.47 % truncated dodecahedron
// 7.78 % cuboctahedron
// 4.62 % icosidodecahedron
// 3.53 % rhombicuboctahedron
// 3.46 % rhombicosidodecahedron
// 7.23 % rhombitruncated cuboctahedron
// 6.93 % rhombitruncated icosidodecahedron
// 3.44 % snub cube
// 3.46 % snub dodecahedron

inline bool operator == (const polyhedron_select_t & x, const polyhedron_select_t & y)
{
  return x.system == y.system && x.point == y.point;
}

namespace
{
  const unsigned probability_max = 1u << 31u;
  const unsigned probability_mask = probability_max - 1u;
  const struct replacement_t {
    polyhedron_select_t before, after;
    unsigned probability;
  } replacements [] = {
    // The fixups in maybe_perform_replacement assume this ordering.
    { { tetrahedral, 0, }, { octahedral,  1, }, unsigned (0.375 * probability_max), },
    { { tetrahedral, 6, }, { octahedral,  5, }, unsigned (0.375 * probability_max), },
    { { tetrahedral, 3, }, { octahedral,  0, }, unsigned (0.375 * probability_max), },
    { { octahedral,  1, }, { tetrahedral, 0, }, unsigned (0.375 * probability_max), },
    { { octahedral,  5, }, { tetrahedral, 6, }, unsigned (0.375 * probability_max), },
    { { octahedral,  0, }, { tetrahedral, 3, }, unsigned (0.375 * probability_max), },
    { { icosahedral, 1, }, { tetrahedral, 7, }, unsigned (0.400 * probability_max), },
    { { tetrahedral, 7, }, { icosahedral, 1, }, unsigned (0.600 * probability_max), },
    // The snub tetrahedron is not chiral (it is the icosahedron).
    // Not doing this replacement makes some snub-desnub combos impossible.
    { { tetrahedral, 7, }, { dual_tetrahedral, 7, }, probability_max / 2, },
  };
  const unsigned replacement_count = sizeof replacements / sizeof * replacements;
  ALIGNED16 const float rotations [3] [4] = {
    // Rotate about an X-node through angle pi/4.
    { -0x1.921fb4P-1f, 0.0f, 0.0f, 0.0f, }, // I1 -> T7
    { +0x1.921fb4P-1f, 0.0f, 0.0f, 0.0f, }, // T7 -> I1
    // Rotate about a Z-node through angle approximately 0.2471 pi.
    { +0x1.caf0fcP-2f, +0x1.448542P-1f, 0.0f, 0.0f, }, // T7 -> T7*
  };

  inline bool bernoulli_trial (rng_t & rng, unsigned probability)
  {
    return (rng.get () & probability_mask) < probability;
  }

  inline void maybe_perform_replacement (rng_t & rng, float (& u) [4], polyhedron_select_t & current, unsigned & starting_point)
  {
    // Replacements are in terms of the primary representation so mask out the dual bit for now.
    unsigned duality = current.system & 1;
    current.system = system_select_t (current.system & ~1);
    // If non-snub, maybe switch between dual representations, to permit either
    // variety of any snub or desnub operation that follows. Not doing it now,
    // before the replacements, makes some double-desnub combos impossible.
    unsigned entropy = (unsigned) rng.get (); // Seems a shame to waste it.
    duality ^= entropy & (current.point != 7);

    unsigned m = 0;
    while (m != replacement_count && ! (replacements [m].before == current && bernoulli_trial (rng, replacements [m].probability))) ++ m;
    if (m != replacement_count) {
      current = replacements [m].after;
      // Fixups after the replacement: avoid backtracking transitions
      // by updating starting_point, and maybe appply a rotation.
      if (m < 6) {
        // Tetrahedral <-> octahedral; if the starting polyhedron exists in both
        // tilings, forbid backtracking to it; otherwise, no transition is forbidden.
        // The fundamental triangles of the tetrahedral and octahedral tilings
        // are chosen so that no rotation is needed after these replacements.
        unsigned j = 0;
        while (j != 3 && starting_point != replacements [m / 3 + j].before.point) ++ j;
        starting_point = j == 3 ? current.point : replacements [m / 3 + j].after.point;
      }
      else {
        // Apply a rotation in object co-ordinates.
        v4f rotation = load4f (rotations [m - 6]);
        if (duality) rotation = - rotation;
        store4f (u, rotate (load4f (u), rotation));
        // Tetrahedral <-> icosahedral: no Markov transition is forbidden after these replacements.
        // Tetrahedral -> dual tetrahedral (both snub): keep the starting_point we already have.
        if (m < 8) starting_point = current.point;
      }
    }

    // If non-snub, maybe switch between dual representations (again).
    // Not doing this now, after the replacement, makes some double-snub combos impossible.
    duality ^= (entropy >> 1) & (current.point != 7);
    // Restore the dual bit.
    current.system = system_select_t (current.system ^ duality);
  }
}

void transition (rng_t & rng, float (& u) [4], polyhedron_select_t & current, unsigned & starting_point)
{
  maybe_perform_replacement (rng, u, current, starting_point);

  // Perform a Markov transition.
  unsigned next;
  do next = rng.get () & 7; /* PLEASE */

  // Certain transitions are not allowed:
  while (next == starting_point || 1 & current.point ["\017\027\047\271\272\274\300\370"] >> next);

  starting_point = current.point;
  current.point = next;
}
<commit_msg>markov.cpp: fix 1-ulp error in hexfloat constant.<commit_after>#include "markov.h"
#include "random.h"
#include "rodrigues.h"
#include "compiler.h"

// The procedure below gives rise to roughly the following relative polyhedron abundancies.

// 8.10 % tetrahedron
// 8.66 % octahedron
// 4.68 % cube
// 7.70 % icosahedron
// 4.62 % dodecahedron
// 5.81 % truncated tetrahedron
// 9.55 % truncated octahedron
// 3.48 % truncated cube
// 3.46 % truncated icosahedron
// 3.47 % truncated dodecahedron
// 7.78 % cuboctahedron
// 4.62 % icosidodecahedron
// 3.53 % rhombicuboctahedron
// 3.46 % rhombicosidodecahedron
// 7.23 % rhombitruncated cuboctahedron
// 6.93 % rhombitruncated icosidodecahedron
// 3.44 % snub cube
// 3.46 % snub dodecahedron

inline bool operator == (const polyhedron_select_t & x, const polyhedron_select_t & y)
{
  return x.system == y.system && x.point == y.point;
}

namespace
{
  const unsigned probability_max = 1u << 31u;
  const unsigned probability_mask = probability_max - 1u;
  const struct replacement_t {
    polyhedron_select_t before, after;
    unsigned probability;
  } replacements [] = {
    // The fixups in maybe_perform_replacement assume this ordering.
    { { tetrahedral, 0, }, { octahedral,  1, }, unsigned (0.375 * probability_max), },
    { { tetrahedral, 6, }, { octahedral,  5, }, unsigned (0.375 * probability_max), },
    { { tetrahedral, 3, }, { octahedral,  0, }, unsigned (0.375 * probability_max), },
    { { octahedral,  1, }, { tetrahedral, 0, }, unsigned (0.375 * probability_max), },
    { { octahedral,  5, }, { tetrahedral, 6, }, unsigned (0.375 * probability_max), },
    { { octahedral,  0, }, { tetrahedral, 3, }, unsigned (0.375 * probability_max), },
    { { icosahedral, 1, }, { tetrahedral, 7, }, unsigned (0.400 * probability_max), },
    { { tetrahedral, 7, }, { icosahedral, 1, }, unsigned (0.600 * probability_max), },
    // The snub tetrahedron is not chiral (it is the icosahedron).
    // Not doing this replacement makes some snub-desnub combos impossible.
    { { tetrahedral, 7, }, { dual_tetrahedral, 7, }, probability_max / 2, },
  };
  const unsigned replacement_count = sizeof replacements / sizeof * replacements;
  ALIGNED16 const float rotations [3] [4] = {
    // Rotate about an X-node through angle pi/4.
    { -0x1.921fb6P-1f, 0.0f, 0.0f, 0.0f, }, // I1 -> T7
    { +0x1.921fb6P-1f, 0.0f, 0.0f, 0.0f, }, // T7 -> I1
    // Rotate about a Z-node through angle approximately 0.2471 pi.
    { +0x1.caf0fcP-2f, +0x1.448542P-1f, 0.0f, 0.0f, }, // T7 -> T7*
  };

  inline bool bernoulli_trial (rng_t & rng, unsigned probability)
  {
    return (rng.get () & probability_mask) < probability;
  }

  inline void maybe_perform_replacement (rng_t & rng, float (& u) [4], polyhedron_select_t & current, unsigned & starting_point)
  {
    // Replacements are in terms of the primary representation so mask out the dual bit for now.
    unsigned duality = current.system & 1;
    current.system = system_select_t (current.system & ~1);
    // If non-snub, maybe switch between dual representations, to permit either
    // variety of any snub or desnub operation that follows. Not doing it now,
    // before the replacements, makes some double-desnub combos impossible.
    unsigned entropy = (unsigned) rng.get (); // Seems a shame to waste it.
    duality ^= entropy & (current.point != 7);

    unsigned m = 0;
    while (m != replacement_count && ! (replacements [m].before == current && bernoulli_trial (rng, replacements [m].probability))) ++ m;
    if (m != replacement_count) {
      current = replacements [m].after;
      // Fixups after the replacement: avoid backtracking transitions
      // by updating starting_point, and maybe appply a rotation.
      if (m < 6) {
        // Tetrahedral <-> octahedral; if the starting polyhedron exists in both
        // tilings, forbid backtracking to it; otherwise, no transition is forbidden.
        // The fundamental triangles of the tetrahedral and octahedral tilings
        // are chosen so that no rotation is needed after these replacements.
        unsigned j = 0;
        while (j != 3 && starting_point != replacements [m / 3 + j].before.point) ++ j;
        starting_point = j == 3 ? current.point : replacements [m / 3 + j].after.point;
      }
      else {
        // Apply a rotation in object co-ordinates.
        v4f rotation = load4f (rotations [m - 6]);
        if (duality) rotation = - rotation;
        store4f (u, rotate (load4f (u), rotation));
        // Tetrahedral <-> icosahedral: no Markov transition is forbidden after these replacements.
        // Tetrahedral -> dual tetrahedral (both snub): keep the starting_point we already have.
        if (m < 8) starting_point = current.point;
      }
    }

    // If non-snub, maybe switch between dual representations (again).
    // Not doing this now, after the replacement, makes some double-snub combos impossible.
    duality ^= (entropy >> 1) & (current.point != 7);
    // Restore the dual bit.
    current.system = system_select_t (current.system ^ duality);
  }
}

void transition (rng_t & rng, float (& u) [4], polyhedron_select_t & current, unsigned & starting_point)
{
  maybe_perform_replacement (rng, u, current, starting_point);

  // Perform a Markov transition.
  unsigned next;
  do next = rng.get () & 7; /* PLEASE */

  // Certain transitions are not allowed:
  while (next == starting_point || 1 & current.point ["\017\027\047\271\272\274\300\370"] >> next);

  starting_point = current.point;
  current.point = next;
}
<|endoftext|>


<commit_before>//===-- ParameterAttributes.cpp - Implement ParamAttrsList ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ParamAttrsList class and ParamAttr utilities.
//
//===----------------------------------------------------------------------===//

#include "llvm/ParamAttrsList.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Support/ManagedStatic.h"
#include <sstream>

using namespace llvm;

static ManagedStatic<FoldingSet<ParamAttrsList> > ParamAttrsLists;

ParamAttrsList::ParamAttrsList(const ParamAttrsVector &attrVec)
  : attrs(attrVec), refCount(0) {
}

ParamAttrsList::~ParamAttrsList() {
  ParamAttrsLists->RemoveNode(this);
}

ParameterAttributes
ParamAttrsList::getParamAttrs(uint16_t Index) const {
  unsigned limit = attrs.size();
  for (unsigned i = 0; i < limit && attrs[i].index <= Index; ++i)
    if (attrs[i].index == Index)
      return attrs[i].attrs;
  return ParamAttr::None;
}

bool ParamAttrsList::hasAttrSomewhere(ParameterAttributes attr) const {
  for (unsigned i = 0, e = attrs.size(); i < e; ++i)
    if (attrs[i].attrs & attr)
      return true;
  return false;
}

std::string
ParamAttrsList::getParamAttrsText(ParameterAttributes Attrs) {
  std::string Result;
  if (Attrs & ParamAttr::ZExt)
    Result += "zeroext ";
  if (Attrs & ParamAttr::SExt)
    Result += "signext ";
  if (Attrs & ParamAttr::NoReturn)
    Result += "noreturn ";
  if (Attrs & ParamAttr::NoUnwind)
    Result += "nounwind ";
  if (Attrs & ParamAttr::InReg)
    Result += "inreg ";
  if (Attrs & ParamAttr::NoAlias)
    Result += "noalias ";
  if (Attrs & ParamAttr::StructRet)
    Result += "sret ";
  if (Attrs & ParamAttr::ByVal)
    Result += "byval ";
  if (Attrs & ParamAttr::Nest)
    Result += "nest ";
  if (Attrs & ParamAttr::ReadNone)
    Result += "readnone ";
  if (Attrs & ParamAttr::ReadOnly)
    Result += "readonly ";
  if (Attrs & ParamAttr::Alignment) {
    std::stringstream s;
    s << ((Attrs & ParamAttr::Alignment) >> 16);
    Result += "align ";
    Result += s.str();
    Result += " ";
  }
  return Result;
}

void ParamAttrsList::Profile(FoldingSetNodeID &ID,
                             const ParamAttrsVector &Attrs) {
  for (unsigned i = 0; i < Attrs.size(); ++i)
    ID.AddInteger(uint64_t(Attrs[i].attrs) << 16 | unsigned(Attrs[i].index));
}

const ParamAttrsList *
ParamAttrsList::get(const ParamAttrsVector &attrVec) {
  // If there are no attributes then return a null ParamAttrsList pointer.
  if (attrVec.empty())
    return 0;

#ifndef NDEBUG
  for (unsigned i = 0, e = attrVec.size(); i < e; ++i) {
    assert(attrVec[i].attrs != ParamAttr::None
           && "Pointless parameter attribute!");
    assert((!i || attrVec[i-1].index < attrVec[i].index)
           && "Misordered ParamAttrsList!");
  }
#endif

  // Otherwise, build a key to look up the existing attributes.
  FoldingSetNodeID ID;
  ParamAttrsList::Profile(ID, attrVec);
  void *InsertPos;
  ParamAttrsList *PAL = ParamAttrsLists->FindNodeOrInsertPos(ID, InsertPos);

  // If we didn't find any existing attributes of the same shape then
  // create a new one and insert it.
  if (!PAL) {
    PAL = new ParamAttrsList(attrVec);
    ParamAttrsLists->InsertNode(PAL, InsertPos);
  }

  // Return the ParamAttrsList that we found or created.
  return PAL;
}

const ParamAttrsList *
ParamAttrsList::getModified(const ParamAttrsList *PAL,
                            const ParamAttrsVector &modVec) {
  if (modVec.empty())
    return PAL;

#ifndef NDEBUG
  for (unsigned i = 0, e = modVec.size(); i < e; ++i)
    assert((!i || modVec[i-1].index < modVec[i].index)
           && "Misordered ParamAttrsList!");
#endif

  if (!PAL) {
    // Strip any instances of ParamAttr::None from modVec before calling 'get'.
    ParamAttrsVector newVec;
    newVec.reserve(modVec.size());
    for (unsigned i = 0, e = modVec.size(); i < e; ++i)
      if (modVec[i].attrs != ParamAttr::None)
        newVec.push_back(modVec[i]);
    return get(newVec);
  }

  const ParamAttrsVector &oldVec = PAL->attrs;

  ParamAttrsVector newVec;
  unsigned oldI = 0;
  unsigned modI = 0;
  unsigned oldE = oldVec.size();
  unsigned modE = modVec.size();

  while (oldI < oldE && modI < modE) {
    uint16_t oldIndex = oldVec[oldI].index;
    uint16_t modIndex = modVec[modI].index;

    if (oldIndex < modIndex) {
      newVec.push_back(oldVec[oldI]);
      ++oldI;
    } else if (modIndex < oldIndex) {
      if (modVec[modI].attrs != ParamAttr::None)
        newVec.push_back(modVec[modI]);
      ++modI;
    } else {
      // Same index - overwrite or delete existing attributes.
      if (modVec[modI].attrs != ParamAttr::None)
        newVec.push_back(modVec[modI]);
      ++oldI;
      ++modI;
    }
  }

  for (; oldI < oldE; ++oldI)
    newVec.push_back(oldVec[oldI]);
  for (; modI < modE; ++modI)
    if (modVec[modI].attrs != ParamAttr::None)
      newVec.push_back(modVec[modI]);

  return get(newVec);
}

const ParamAttrsList *
ParamAttrsList::includeAttrs(const ParamAttrsList *PAL,
                             uint16_t idx, ParameterAttributes attrs) {
  ParameterAttributes OldAttrs = PAL ? PAL->getParamAttrs(idx) :
                                       ParamAttr::None;
#ifndef NDEBUG
  // FIXME it is not obvious how this should work for alignment.
  // For now, say we can't change a known alignment.
  ParameterAttributes OldAlign = OldAttrs & ParamAttr::Alignment;
  ParameterAttributes NewAlign = attrs & ParamAttr::Alignment;
  assert((!OldAlign || !NewAlign || OldAlign == NewAlign) &&
         "Attempt to change alignment!");
#endif

  ParameterAttributes NewAttrs = OldAttrs | attrs;
  if (NewAttrs == OldAttrs)
    return PAL;

  ParamAttrsVector modVec(1);
  modVec[0] = ParamAttrsWithIndex::get(idx, NewAttrs);
  return getModified(PAL, modVec);
}

const ParamAttrsList *
ParamAttrsList::excludeAttrs(const ParamAttrsList *PAL,
                             uint16_t idx, ParameterAttributes attrs) {
#ifndef NDEBUG
  // FIXME it is not obvious how this should work for alignment.
  // For now, say we can't pass in alignment, which no current use does.
  assert(!(attrs & ParamAttr::Alignment) && "Attempt to exclude alignment!");
#endif
  ParameterAttributes OldAttrs = PAL ? PAL->getParamAttrs(idx) :
                                       ParamAttr::None;
  ParameterAttributes NewAttrs = OldAttrs & ~attrs;
  if (NewAttrs == OldAttrs)
    return PAL;

  ParamAttrsVector modVec(1);
  modVec[0] = ParamAttrsWithIndex::get(idx, NewAttrs);
  return getModified(PAL, modVec);
}

ParameterAttributes ParamAttr::typeIncompatible (const Type *Ty) {
  ParameterAttributes Incompatible = None;

  if (!Ty->isInteger())
    // Attributes that only apply to integers.
    Incompatible |= SExt | ZExt;

  if (!isa<PointerType>(Ty))
    // Attributes that only apply to pointers.
    Incompatible |= ByVal | Nest | NoAlias | StructRet;

  return Incompatible;
}
<commit_msg>Use utostr instead of a stringstream.<commit_after>//===-- ParameterAttributes.cpp - Implement ParamAttrsList ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ParamAttrsList class and ParamAttr utilities.
//
//===----------------------------------------------------------------------===//

#include "llvm/ParamAttrsList.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ManagedStatic.h"

using namespace llvm;

static ManagedStatic<FoldingSet<ParamAttrsList> > ParamAttrsLists;

ParamAttrsList::ParamAttrsList(const ParamAttrsVector &attrVec)
  : attrs(attrVec), refCount(0) {
}

ParamAttrsList::~ParamAttrsList() {
  ParamAttrsLists->RemoveNode(this);
}

ParameterAttributes
ParamAttrsList::getParamAttrs(uint16_t Index) const {
  unsigned limit = attrs.size();
  for (unsigned i = 0; i < limit && attrs[i].index <= Index; ++i)
    if (attrs[i].index == Index)
      return attrs[i].attrs;
  return ParamAttr::None;
}

bool ParamAttrsList::hasAttrSomewhere(ParameterAttributes attr) const {
  for (unsigned i = 0, e = attrs.size(); i < e; ++i)
    if (attrs[i].attrs & attr)
      return true;
  return false;
}

std::string
ParamAttrsList::getParamAttrsText(ParameterAttributes Attrs) {
  std::string Result;
  if (Attrs & ParamAttr::ZExt)
    Result += "zeroext ";
  if (Attrs & ParamAttr::SExt)
    Result += "signext ";
  if (Attrs & ParamAttr::NoReturn)
    Result += "noreturn ";
  if (Attrs & ParamAttr::NoUnwind)
    Result += "nounwind ";
  if (Attrs & ParamAttr::InReg)
    Result += "inreg ";
  if (Attrs & ParamAttr::NoAlias)
    Result += "noalias ";
  if (Attrs & ParamAttr::StructRet)
    Result += "sret ";
  if (Attrs & ParamAttr::ByVal)
    Result += "byval ";
  if (Attrs & ParamAttr::Nest)
    Result += "nest ";
  if (Attrs & ParamAttr::ReadNone)
    Result += "readnone ";
  if (Attrs & ParamAttr::ReadOnly)
    Result += "readonly ";
  if (Attrs & ParamAttr::Alignment) {
    Result += "align ";
    Result += utostr((Attrs & ParamAttr::Alignment) >> 16);
    Result += " ";
  }
  return Result;
}

void ParamAttrsList::Profile(FoldingSetNodeID &ID,
                             const ParamAttrsVector &Attrs) {
  for (unsigned i = 0; i < Attrs.size(); ++i)
    ID.AddInteger(uint64_t(Attrs[i].attrs) << 16 | unsigned(Attrs[i].index));
}

const ParamAttrsList *
ParamAttrsList::get(const ParamAttrsVector &attrVec) {
  // If there are no attributes then return a null ParamAttrsList pointer.
  if (attrVec.empty())
    return 0;

#ifndef NDEBUG
  for (unsigned i = 0, e = attrVec.size(); i < e; ++i) {
    assert(attrVec[i].attrs != ParamAttr::None
           && "Pointless parameter attribute!");
    assert((!i || attrVec[i-1].index < attrVec[i].index)
           && "Misordered ParamAttrsList!");
  }
#endif

  // Otherwise, build a key to look up the existing attributes.
  FoldingSetNodeID ID;
  ParamAttrsList::Profile(ID, attrVec);
  void *InsertPos;
  ParamAttrsList *PAL = ParamAttrsLists->FindNodeOrInsertPos(ID, InsertPos);

  // If we didn't find any existing attributes of the same shape then
  // create a new one and insert it.
  if (!PAL) {
    PAL = new ParamAttrsList(attrVec);
    ParamAttrsLists->InsertNode(PAL, InsertPos);
  }

  // Return the ParamAttrsList that we found or created.
  return PAL;
}

const ParamAttrsList *
ParamAttrsList::getModified(const ParamAttrsList *PAL,
                            const ParamAttrsVector &modVec) {
  if (modVec.empty())
    return PAL;

#ifndef NDEBUG
  for (unsigned i = 0, e = modVec.size(); i < e; ++i)
    assert((!i || modVec[i-1].index < modVec[i].index)
           && "Misordered ParamAttrsList!");
#endif

  if (!PAL) {
    // Strip any instances of ParamAttr::None from modVec before calling 'get'.
    ParamAttrsVector newVec;
    newVec.reserve(modVec.size());
    for (unsigned i = 0, e = modVec.size(); i < e; ++i)
      if (modVec[i].attrs != ParamAttr::None)
        newVec.push_back(modVec[i]);
    return get(newVec);
  }

  const ParamAttrsVector &oldVec = PAL->attrs;

  ParamAttrsVector newVec;
  unsigned oldI = 0;
  unsigned modI = 0;
  unsigned oldE = oldVec.size();
  unsigned modE = modVec.size();

  while (oldI < oldE && modI < modE) {
    uint16_t oldIndex = oldVec[oldI].index;
    uint16_t modIndex = modVec[modI].index;

    if (oldIndex < modIndex) {
      newVec.push_back(oldVec[oldI]);
      ++oldI;
    } else if (modIndex < oldIndex) {
      if (modVec[modI].attrs != ParamAttr::None)
        newVec.push_back(modVec[modI]);
      ++modI;
    } else {
      // Same index - overwrite or delete existing attributes.
      if (modVec[modI].attrs != ParamAttr::None)
        newVec.push_back(modVec[modI]);
      ++oldI;
      ++modI;
    }
  }

  for (; oldI < oldE; ++oldI)
    newVec.push_back(oldVec[oldI]);
  for (; modI < modE; ++modI)
    if (modVec[modI].attrs != ParamAttr::None)
      newVec.push_back(modVec[modI]);

  return get(newVec);
}

const ParamAttrsList *
ParamAttrsList::includeAttrs(const ParamAttrsList *PAL,
                             uint16_t idx, ParameterAttributes attrs) {
  ParameterAttributes OldAttrs = PAL ? PAL->getParamAttrs(idx) :
                                       ParamAttr::None;
#ifndef NDEBUG
  // FIXME it is not obvious how this should work for alignment.
  // For now, say we can't change a known alignment.
  ParameterAttributes OldAlign = OldAttrs & ParamAttr::Alignment;
  ParameterAttributes NewAlign = attrs & ParamAttr::Alignment;
  assert((!OldAlign || !NewAlign || OldAlign == NewAlign) &&
         "Attempt to change alignment!");
#endif

  ParameterAttributes NewAttrs = OldAttrs | attrs;
  if (NewAttrs == OldAttrs)
    return PAL;

  ParamAttrsVector modVec(1);
  modVec[0] = ParamAttrsWithIndex::get(idx, NewAttrs);
  return getModified(PAL, modVec);
}

const ParamAttrsList *
ParamAttrsList::excludeAttrs(const ParamAttrsList *PAL,
                             uint16_t idx, ParameterAttributes attrs) {
#ifndef NDEBUG
  // FIXME it is not obvious how this should work for alignment.
  // For now, say we can't pass in alignment, which no current use does.
  assert(!(attrs & ParamAttr::Alignment) && "Attempt to exclude alignment!");
#endif
  ParameterAttributes OldAttrs = PAL ? PAL->getParamAttrs(idx) :
                                       ParamAttr::None;
  ParameterAttributes NewAttrs = OldAttrs & ~attrs;
  if (NewAttrs == OldAttrs)
    return PAL;

  ParamAttrsVector modVec(1);
  modVec[0] = ParamAttrsWithIndex::get(idx, NewAttrs);
  return getModified(PAL, modVec);
}

ParameterAttributes ParamAttr::typeIncompatible (const Type *Ty) {
  ParameterAttributes Incompatible = None;

  if (!Ty->isInteger())
    // Attributes that only apply to integers.
    Incompatible |= SExt | ZExt;

  if (!isa<PointerType>(Ty))
    // Attributes that only apply to pointers.
    Incompatible |= ByVal | Nest | NoAlias | StructRet;

  return Incompatible;
}
<|endoftext|>


<commit_before>//===-- AMDGPUAsmPrinter.cpp - AMDGPU Assebly printer  --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
///
/// The AMDGPUAsmPrinter is used to print both assembly string and also binary
/// code.  When passed an MCAsmStreamer it prints assembly and when passed
/// an MCObjectStreamer it outputs binary code.
//
//===----------------------------------------------------------------------===//
//

#include "AMDGPUAsmPrinter.h"
#include "AMDGPU.h"
#include "R600Defines.h"
#include "R600MachineFunctionInfo.h"
#include "R600RegisterInfo.h"
#include "SIDefines.h"
#include "SIMachineFunctionInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetLoweringObjectFile.h"

using namespace llvm;

static AsmPrinter *createAMDGPUAsmPrinterPass(TargetMachine &tm,
                                              MCStreamer &Streamer) {
  return new AMDGPUAsmPrinter(tm, Streamer);
}

extern "C" void LLVMInitializeR600AsmPrinter() {
  TargetRegistry::RegisterAsmPrinter(TheAMDGPUTarget, createAMDGPUAsmPrinterPass);
}

AMDGPUAsmPrinter::AMDGPUAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
    : AsmPrinter(TM, Streamer)
{
  DisasmEnabled = TM.getSubtarget<AMDGPUSubtarget>().dumpCode() &&
                  ! Streamer.hasRawTextSupport();
}

/// We need to override this function so we can avoid
/// the call to EmitFunctionHeader(), which the MCPureStreamer can't handle.
bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
  SetupMachineFunction(MF);
  if (OutStreamer.hasRawTextSupport()) {
    OutStreamer.EmitRawText("@" + MF.getName() + ":");
  }

  MCContext &Context = getObjFileLowering().getContext();
  const MCSectionELF *ConfigSection = Context.getELFSection(".AMDGPU.config",
                                              ELF::SHT_PROGBITS, 0,
                                              SectionKind::getReadOnly());
  OutStreamer.SwitchSection(ConfigSection);
  const AMDGPUSubtarget &STM = TM.getSubtarget<AMDGPUSubtarget>();
  if (STM.getGeneration() > AMDGPUSubtarget::NORTHERN_ISLANDS) {
    EmitProgramInfoSI(MF);
  } else {
    EmitProgramInfoR600(MF);
  }

  DisasmLines.clear();
  HexLines.clear();
  DisasmLineMaxLen = 0;

  OutStreamer.SwitchSection(getObjFileLowering().getTextSection());
  EmitFunctionBody();

  if (STM.dumpCode()) {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
    MF.dump();
#endif

    if (DisasmEnabled) {
      OutStreamer.SwitchSection(Context.getELFSection(".AMDGPU.disasm",
                                                  ELF::SHT_NOTE, 0,
                                                  SectionKind::getReadOnly()));

      for (size_t i = 0; i < DisasmLines.size(); ++i) {
        std::string Comment(DisasmLineMaxLen - DisasmLines[i].size(), ' ');
        Comment += " ; " + HexLines[i] + "\n";

        OutStreamer.EmitBytes(StringRef(DisasmLines[i]));
        OutStreamer.EmitBytes(StringRef(Comment));
      }
    }
  }

  return false;
}

void AMDGPUAsmPrinter::EmitProgramInfoR600(MachineFunction &MF) {
  unsigned MaxGPR = 0;
  bool killPixel = false;
  const R600RegisterInfo * RI =
                static_cast<const R600RegisterInfo*>(TM.getRegisterInfo());
  R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
  const AMDGPUSubtarget &STM = TM.getSubtarget<AMDGPUSubtarget>();

  for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
                                                  BB != BB_E; ++BB) {
    MachineBasicBlock &MBB = *BB;
    for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
                                                    I != E; ++I) {
      MachineInstr &MI = *I;
      if (MI.getOpcode() == AMDGPU::KILLGT)
        killPixel = true;
      unsigned numOperands = MI.getNumOperands();
      for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) {
        MachineOperand & MO = MI.getOperand(op_idx);
        if (!MO.isReg())
          continue;
        unsigned HWReg = RI->getEncodingValue(MO.getReg()) & 0xff;

        // Register with value > 127 aren't GPR
        if (HWReg > 127)
          continue;
        MaxGPR = std::max(MaxGPR, HWReg);
      }
    }
  }

  unsigned RsrcReg;
  if (STM.getGeneration() >= AMDGPUSubtarget::EVERGREEN) {
    // Evergreen / Northern Islands
    switch (MFI->ShaderType) {
    default: // Fall through
    case ShaderType::COMPUTE:  RsrcReg = R_0288D4_SQ_PGM_RESOURCES_LS; break;
    case ShaderType::GEOMETRY: RsrcReg = R_028878_SQ_PGM_RESOURCES_GS; break;
    case ShaderType::PIXEL:    RsrcReg = R_028844_SQ_PGM_RESOURCES_PS; break;
    case ShaderType::VERTEX:   RsrcReg = R_028860_SQ_PGM_RESOURCES_VS; break;
    }
  } else {
    // R600 / R700
    switch (MFI->ShaderType) {
    default: // Fall through
    case ShaderType::GEOMETRY: // Fall through
    case ShaderType::COMPUTE:  // Fall through
    case ShaderType::VERTEX:   RsrcReg = R_028868_SQ_PGM_RESOURCES_VS; break;
    case ShaderType::PIXEL:    RsrcReg = R_028850_SQ_PGM_RESOURCES_PS; break;
    }
  }

  OutStreamer.EmitIntValue(RsrcReg, 4);
  OutStreamer.EmitIntValue(S_NUM_GPRS(MaxGPR + 1) |
                           S_STACK_SIZE(MFI->StackSize), 4);
  OutStreamer.EmitIntValue(R_02880C_DB_SHADER_CONTROL, 4);
  OutStreamer.EmitIntValue(S_02880C_KILL_ENABLE(killPixel), 4);

  if (MFI->ShaderType == ShaderType::COMPUTE) {
    OutStreamer.EmitIntValue(R_0288E8_SQ_LDS_ALLOC, 4);
    OutStreamer.EmitIntValue(RoundUpToAlignment(MFI->LDSSize, 4) >> 2, 4);
  }
}

void AMDGPUAsmPrinter::EmitProgramInfoSI(MachineFunction &MF) {
  unsigned MaxSGPR = 0;
  unsigned MaxVGPR = 0;
  bool VCCUsed = false;
  const SIRegisterInfo * RI =
                static_cast<const SIRegisterInfo*>(TM.getRegisterInfo());

  for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
                                                  BB != BB_E; ++BB) {
    MachineBasicBlock &MBB = *BB;
    for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
                                                    I != E; ++I) {
      MachineInstr &MI = *I;

      unsigned numOperands = MI.getNumOperands();
      for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) {
        MachineOperand & MO = MI.getOperand(op_idx);
        unsigned maxUsed;
        unsigned width = 0;
        bool isSGPR = false;
        unsigned reg;
        unsigned hwReg;
        if (!MO.isReg()) {
          continue;
        }
        reg = MO.getReg();
        if (reg == AMDGPU::VCC) {
          VCCUsed = true;
          continue;
        }
        switch (reg) {
        default: break;
        case AMDGPU::EXEC:
        case AMDGPU::M0:
          continue;
        }

        if (AMDGPU::SReg_32RegClass.contains(reg)) {
          isSGPR = true;
          width = 1;
        } else if (AMDGPU::VReg_32RegClass.contains(reg)) {
          isSGPR = false;
          width = 1;
        } else if (AMDGPU::SReg_64RegClass.contains(reg)) {
          isSGPR = true;
          width = 2;
        } else if (AMDGPU::VReg_64RegClass.contains(reg)) {
          isSGPR = false;
          width = 2;
        } else if (AMDGPU::VReg_96RegClass.contains(reg)) {
          isSGPR = false;
          width = 3;
        } else if (AMDGPU::SReg_128RegClass.contains(reg)) {
          isSGPR = true;
          width = 4;
        } else if (AMDGPU::VReg_128RegClass.contains(reg)) {
          isSGPR = false;
          width = 4;
        } else if (AMDGPU::SReg_256RegClass.contains(reg)) {
          isSGPR = true;
          width = 8;
        } else if (AMDGPU::VReg_256RegClass.contains(reg)) {
          isSGPR = false;
          width = 8;
        } else if (AMDGPU::VReg_512RegClass.contains(reg)) {
          isSGPR = false;
          width = 16;
        } else {
          assert(!"Unknown register class");
        }
        hwReg = RI->getEncodingValue(reg) & 0xff;
        maxUsed = hwReg + width - 1;
        if (isSGPR) {
          MaxSGPR = maxUsed > MaxSGPR ? maxUsed : MaxSGPR;
        } else {
          MaxVGPR = maxUsed > MaxVGPR ? maxUsed : MaxVGPR;
        }
      }
    }
  }
  if (VCCUsed) {
    MaxSGPR += 2;
  }
  SIMachineFunctionInfo * MFI = MF.getInfo<SIMachineFunctionInfo>();
  unsigned RsrcReg;
  switch (MFI->ShaderType) {
  default: // Fall through
  case ShaderType::COMPUTE:  RsrcReg = R_00B848_COMPUTE_PGM_RSRC1; break;
  case ShaderType::GEOMETRY: RsrcReg = R_00B228_SPI_SHADER_PGM_RSRC1_GS; break;
  case ShaderType::PIXEL:    RsrcReg = R_00B028_SPI_SHADER_PGM_RSRC1_PS; break;
  case ShaderType::VERTEX:   RsrcReg = R_00B128_SPI_SHADER_PGM_RSRC1_VS; break;
  }

  OutStreamer.EmitIntValue(RsrcReg, 4);
  OutStreamer.EmitIntValue(S_00B028_VGPRS(MaxVGPR / 4) | S_00B028_SGPRS(MaxSGPR / 8), 4);

  if (MFI->ShaderType == ShaderType::COMPUTE) {
    OutStreamer.EmitIntValue(R_00B84C_COMPUTE_PGM_RSRC2, 4);
    OutStreamer.EmitIntValue(S_00B84C_LDS_SIZE(RoundUpToAlignment(MFI->LDSSize, 256) >> 8), 4);
  }
  if (MFI->ShaderType == ShaderType::PIXEL) {
    OutStreamer.EmitIntValue(R_00B02C_SPI_SHADER_PGM_RSRC2_PS, 4);
    OutStreamer.EmitIntValue(S_00B02C_EXTRA_LDS_SIZE(RoundUpToAlignment(MFI->LDSSize, 256) >> 8), 4);
    OutStreamer.EmitIntValue(R_0286CC_SPI_PS_INPUT_ENA, 4);
    OutStreamer.EmitIntValue(MFI->PSInputAddr, 4);
  }
}
<commit_msg>R600/SI: Don't assert on SCC usage<commit_after>//===-- AMDGPUAsmPrinter.cpp - AMDGPU Assebly printer  --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
///
/// The AMDGPUAsmPrinter is used to print both assembly string and also binary
/// code.  When passed an MCAsmStreamer it prints assembly and when passed
/// an MCObjectStreamer it outputs binary code.
//
//===----------------------------------------------------------------------===//
//

#include "AMDGPUAsmPrinter.h"
#include "AMDGPU.h"
#include "R600Defines.h"
#include "R600MachineFunctionInfo.h"
#include "R600RegisterInfo.h"
#include "SIDefines.h"
#include "SIMachineFunctionInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetLoweringObjectFile.h"

using namespace llvm;

static AsmPrinter *createAMDGPUAsmPrinterPass(TargetMachine &tm,
                                              MCStreamer &Streamer) {
  return new AMDGPUAsmPrinter(tm, Streamer);
}

extern "C" void LLVMInitializeR600AsmPrinter() {
  TargetRegistry::RegisterAsmPrinter(TheAMDGPUTarget, createAMDGPUAsmPrinterPass);
}

AMDGPUAsmPrinter::AMDGPUAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
    : AsmPrinter(TM, Streamer)
{
  DisasmEnabled = TM.getSubtarget<AMDGPUSubtarget>().dumpCode() &&
                  ! Streamer.hasRawTextSupport();
}

/// We need to override this function so we can avoid
/// the call to EmitFunctionHeader(), which the MCPureStreamer can't handle.
bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
  SetupMachineFunction(MF);
  if (OutStreamer.hasRawTextSupport()) {
    OutStreamer.EmitRawText("@" + MF.getName() + ":");
  }

  MCContext &Context = getObjFileLowering().getContext();
  const MCSectionELF *ConfigSection = Context.getELFSection(".AMDGPU.config",
                                              ELF::SHT_PROGBITS, 0,
                                              SectionKind::getReadOnly());
  OutStreamer.SwitchSection(ConfigSection);
  const AMDGPUSubtarget &STM = TM.getSubtarget<AMDGPUSubtarget>();
  if (STM.getGeneration() > AMDGPUSubtarget::NORTHERN_ISLANDS) {
    EmitProgramInfoSI(MF);
  } else {
    EmitProgramInfoR600(MF);
  }

  DisasmLines.clear();
  HexLines.clear();
  DisasmLineMaxLen = 0;

  OutStreamer.SwitchSection(getObjFileLowering().getTextSection());
  EmitFunctionBody();

  if (STM.dumpCode()) {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
    MF.dump();
#endif

    if (DisasmEnabled) {
      OutStreamer.SwitchSection(Context.getELFSection(".AMDGPU.disasm",
                                                  ELF::SHT_NOTE, 0,
                                                  SectionKind::getReadOnly()));

      for (size_t i = 0; i < DisasmLines.size(); ++i) {
        std::string Comment(DisasmLineMaxLen - DisasmLines[i].size(), ' ');
        Comment += " ; " + HexLines[i] + "\n";

        OutStreamer.EmitBytes(StringRef(DisasmLines[i]));
        OutStreamer.EmitBytes(StringRef(Comment));
      }
    }
  }

  return false;
}

void AMDGPUAsmPrinter::EmitProgramInfoR600(MachineFunction &MF) {
  unsigned MaxGPR = 0;
  bool killPixel = false;
  const R600RegisterInfo * RI =
                static_cast<const R600RegisterInfo*>(TM.getRegisterInfo());
  R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>();
  const AMDGPUSubtarget &STM = TM.getSubtarget<AMDGPUSubtarget>();

  for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
                                                  BB != BB_E; ++BB) {
    MachineBasicBlock &MBB = *BB;
    for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
                                                    I != E; ++I) {
      MachineInstr &MI = *I;
      if (MI.getOpcode() == AMDGPU::KILLGT)
        killPixel = true;
      unsigned numOperands = MI.getNumOperands();
      for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) {
        MachineOperand & MO = MI.getOperand(op_idx);
        if (!MO.isReg())
          continue;
        unsigned HWReg = RI->getEncodingValue(MO.getReg()) & 0xff;

        // Register with value > 127 aren't GPR
        if (HWReg > 127)
          continue;
        MaxGPR = std::max(MaxGPR, HWReg);
      }
    }
  }

  unsigned RsrcReg;
  if (STM.getGeneration() >= AMDGPUSubtarget::EVERGREEN) {
    // Evergreen / Northern Islands
    switch (MFI->ShaderType) {
    default: // Fall through
    case ShaderType::COMPUTE:  RsrcReg = R_0288D4_SQ_PGM_RESOURCES_LS; break;
    case ShaderType::GEOMETRY: RsrcReg = R_028878_SQ_PGM_RESOURCES_GS; break;
    case ShaderType::PIXEL:    RsrcReg = R_028844_SQ_PGM_RESOURCES_PS; break;
    case ShaderType::VERTEX:   RsrcReg = R_028860_SQ_PGM_RESOURCES_VS; break;
    }
  } else {
    // R600 / R700
    switch (MFI->ShaderType) {
    default: // Fall through
    case ShaderType::GEOMETRY: // Fall through
    case ShaderType::COMPUTE:  // Fall through
    case ShaderType::VERTEX:   RsrcReg = R_028868_SQ_PGM_RESOURCES_VS; break;
    case ShaderType::PIXEL:    RsrcReg = R_028850_SQ_PGM_RESOURCES_PS; break;
    }
  }

  OutStreamer.EmitIntValue(RsrcReg, 4);
  OutStreamer.EmitIntValue(S_NUM_GPRS(MaxGPR + 1) |
                           S_STACK_SIZE(MFI->StackSize), 4);
  OutStreamer.EmitIntValue(R_02880C_DB_SHADER_CONTROL, 4);
  OutStreamer.EmitIntValue(S_02880C_KILL_ENABLE(killPixel), 4);

  if (MFI->ShaderType == ShaderType::COMPUTE) {
    OutStreamer.EmitIntValue(R_0288E8_SQ_LDS_ALLOC, 4);
    OutStreamer.EmitIntValue(RoundUpToAlignment(MFI->LDSSize, 4) >> 2, 4);
  }
}

void AMDGPUAsmPrinter::EmitProgramInfoSI(MachineFunction &MF) {
  unsigned MaxSGPR = 0;
  unsigned MaxVGPR = 0;
  bool VCCUsed = false;
  const SIRegisterInfo * RI =
                static_cast<const SIRegisterInfo*>(TM.getRegisterInfo());

  for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
                                                  BB != BB_E; ++BB) {
    MachineBasicBlock &MBB = *BB;
    for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
                                                    I != E; ++I) {
      MachineInstr &MI = *I;

      unsigned numOperands = MI.getNumOperands();
      for (unsigned op_idx = 0; op_idx < numOperands; op_idx++) {
        MachineOperand & MO = MI.getOperand(op_idx);
        unsigned maxUsed;
        unsigned width = 0;
        bool isSGPR = false;
        unsigned reg;
        unsigned hwReg;
        if (!MO.isReg()) {
          continue;
        }
        reg = MO.getReg();
        if (reg == AMDGPU::VCC) {
          VCCUsed = true;
          continue;
        }

        switch (reg) {
        default: break;
        case AMDGPU::SCC:
        case AMDGPU::EXEC:
        case AMDGPU::M0:
          continue;
        }

        if (AMDGPU::SReg_32RegClass.contains(reg)) {
          isSGPR = true;
          width = 1;
        } else if (AMDGPU::VReg_32RegClass.contains(reg)) {
          isSGPR = false;
          width = 1;
        } else if (AMDGPU::SReg_64RegClass.contains(reg)) {
          isSGPR = true;
          width = 2;
        } else if (AMDGPU::VReg_64RegClass.contains(reg)) {
          isSGPR = false;
          width = 2;
        } else if (AMDGPU::VReg_96RegClass.contains(reg)) {
          isSGPR = false;
          width = 3;
        } else if (AMDGPU::SReg_128RegClass.contains(reg)) {
          isSGPR = true;
          width = 4;
        } else if (AMDGPU::VReg_128RegClass.contains(reg)) {
          isSGPR = false;
          width = 4;
        } else if (AMDGPU::SReg_256RegClass.contains(reg)) {
          isSGPR = true;
          width = 8;
        } else if (AMDGPU::VReg_256RegClass.contains(reg)) {
          isSGPR = false;
          width = 8;
        } else if (AMDGPU::VReg_512RegClass.contains(reg)) {
          isSGPR = false;
          width = 16;
        } else {
          assert(!"Unknown register class");
        }
        hwReg = RI->getEncodingValue(reg) & 0xff;
        maxUsed = hwReg + width - 1;
        if (isSGPR) {
          MaxSGPR = maxUsed > MaxSGPR ? maxUsed : MaxSGPR;
        } else {
          MaxVGPR = maxUsed > MaxVGPR ? maxUsed : MaxVGPR;
        }
      }
    }
  }
  if (VCCUsed) {
    MaxSGPR += 2;
  }
  SIMachineFunctionInfo * MFI = MF.getInfo<SIMachineFunctionInfo>();
  unsigned RsrcReg;
  switch (MFI->ShaderType) {
  default: // Fall through
  case ShaderType::COMPUTE:  RsrcReg = R_00B848_COMPUTE_PGM_RSRC1; break;
  case ShaderType::GEOMETRY: RsrcReg = R_00B228_SPI_SHADER_PGM_RSRC1_GS; break;
  case ShaderType::PIXEL:    RsrcReg = R_00B028_SPI_SHADER_PGM_RSRC1_PS; break;
  case ShaderType::VERTEX:   RsrcReg = R_00B128_SPI_SHADER_PGM_RSRC1_VS; break;
  }

  OutStreamer.EmitIntValue(RsrcReg, 4);
  OutStreamer.EmitIntValue(S_00B028_VGPRS(MaxVGPR / 4) | S_00B028_SGPRS(MaxSGPR / 8), 4);

  if (MFI->ShaderType == ShaderType::COMPUTE) {
    OutStreamer.EmitIntValue(R_00B84C_COMPUTE_PGM_RSRC2, 4);
    OutStreamer.EmitIntValue(S_00B84C_LDS_SIZE(RoundUpToAlignment(MFI->LDSSize, 256) >> 8), 4);
  }
  if (MFI->ShaderType == ShaderType::PIXEL) {
    OutStreamer.EmitIntValue(R_00B02C_SPI_SHADER_PGM_RSRC2_PS, 4);
    OutStreamer.EmitIntValue(S_00B02C_EXTRA_LDS_SIZE(RoundUpToAlignment(MFI->LDSSize, 256) >> 8), 4);
    OutStreamer.EmitIntValue(R_0286CC_SPI_PS_INPUT_ENA, 4);
    OutStreamer.EmitIntValue(MFI->PSInputAddr, 4);
  }
}
<|endoftext|>


<commit_before>//
// Name:	 canvas.cpp
// Purpose:	 Implements the canvas class for the wxWindows application.
//
// Copyright (c) 2001 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "vtlib/vtlib.h"
#include "vtlib/core/TimeEngines.h"
#include "vtlib/core/TerrainScene.h"
#include "../Enviro.h"			// for g_App, GetTerrainScene
#include "canvas.h"
#include "frame.h"
#include "app.h"

DECLARE_APP(vtApp)

/*
 * vtGLCanvas implementation
 */
BEGIN_EVENT_TABLE(vtGLCanvas, wxGLCanvas)
	EVT_CLOSE(vtGLCanvas::OnClose)
	EVT_SIZE(vtGLCanvas::OnSize)
	EVT_PAINT(vtGLCanvas::OnPaint)
	EVT_CHAR(vtGLCanvas::OnChar)
	EVT_MOUSE_EVENTS(vtGLCanvas::OnMouseEvent)
	EVT_ERASE_BACKGROUND(vtGLCanvas::OnEraseBackground)
END_EVENT_TABLE()

static vtGLCanvas *s_canvas = NULL;

vtGLCanvas::vtGLCanvas(wxWindow *parent, wxWindowID id,
	const wxPoint& pos, const wxSize& size, long style, const wxString& name, int* gl_attrib):
  wxGLCanvas(parent, id, pos, size, style, name, gl_attrib)
{
	parent->Show(TRUE);
	SetCurrent();

	m_StatusTimer.SetFrame((wxFrame *)parent);
	m_StatusTimer.Start(1000);

	m_bPainting = false;
	m_bRunning = true;
	m_bShowFrameRateChart = true;

	s_canvas = this;
}

vtGLCanvas::~vtGLCanvas(void)
{
}

void EnableContinuousRendering(bool bTrue)
{
	if (s_canvas)
		s_canvas->m_bRunning = bTrue;
}

void vtGLCanvas::QueueRefresh(bool eraseBackground)
	// A Refresh routine we can call from inside OnPaint.
	//   (queues the events rather than dispatching them immediately).
{
	// With wxGTK, you can't do a Refresh() in OnPaint because it doesn't
	//   queue (post) a Refresh event for later.  Rather it dispatches
	//   (processes) the underlying events immediately via ProcessEvent
	//   (read, recursive call).  See the wxPostEvent docs and Refresh code
	//   for more details.
	if ( eraseBackground )
	{
		wxEraseEvent eevent( GetId() );
		eevent.SetEventObject( this );
		wxPostEvent( GetEventHandler(), eevent );
	}

	wxPaintEvent event( GetId() );
	event.SetEventObject( this );
	wxPostEvent( GetEventHandler(), event );
}

void StatusTimer::Notify()
{
	if (!m_pFrame || !m_pFrame->GetStatusBar()) return;

	vtScene *scene = vtGetScene();
	if (!scene) return;

	// get framerate
	float fps = scene->GetFrameRate();

	// get time of day
	int hr, min, sec;
	GetTerrainScene()->m_pTime->GetTime(hr, min, sec);

	vtString str, str2;
	str.Format("fps %3.1f, time %02d:%02d:%02d, ", fps, hr, min, sec);

	g_App.DescribeCoordinates(str2);
	str += str2;

	// get CLOD triangle counts, if appropriate
	g_App.DescribeCLOD(str2);
	str += str2;

	str += g_App.m_strMessage;

	m_pFrame->SetStatusText((const char *)str);
}

void vtGLCanvas::OnPaint( wxPaintEvent& event )
{
	// place the dc inside a scope, to delete it before the end of function
	if (1)
	{
		// This is a dummy, to avoid an endless succession of paint messages.
		// OnPaint handlers must always create a wxPaintDC.
		wxPaintDC dc(this);
#ifdef __WXMSW__
		if (!GetContext()) return;
#endif

		if (m_bPainting || !m_bRunning) return;

		m_bPainting = true;

		// Render the Scene Graph
		vtGetScene()->DoUpdate();

		if (m_bShowFrameRateChart)
			vtGetScene()->DrawFrameRateChart();

		SwapBuffers();

#ifdef WIN32
		// Call Refresh again for continuous rendering,
		if (m_bRunning)
			Refresh(FALSE);
#else
		// Queue another refresh for continuous rendering.
		//   (Yield first so we don't starve out keyboard & mouse events.)
		//
		// FIXME: We may want to use a frame timer instead of immediate-
		//   redraw so we don't eat so much CPU on machines that can
		//   easily handle the frame rate.
		wxYield();
		QueueRefresh(FALSE);
#endif

		// update the status bar every 1/10 of a second
		static float last_stat = 0.0f;
		float cur = vtGetTime();
		if (cur - last_stat > 0.1f)
		{
			last_stat = cur;
			m_StatusTimer.Notify();
		}

		m_bPainting = false;
	}

	// Must allow some idle processing to occur - or the toolbars will not
	// update, and the close box will not respond!
	wxGetApp().ProcessIdle();
}

void vtGLCanvas::OnClose(wxCloseEvent& event)
{
	m_bRunning = false;
}

void vtGLCanvas::OnSize(wxSizeEvent& event)
{
  // Presumably this is a wxMSWism.
  // For wxGTK & wxMotif, all canvas resize events occur before the context
  //   is set.  So ignore this context check and grab the window width/height
  //   when we get it so it (and derived values such as aspect ratio and
  //   viewport parms) are computed correctly.
#ifdef __WXMSW__
	if (!GetContext()) return;
#endif

	SetCurrent();
	int width, height;
	GetClientSize(& width, & height);

	vtGetScene()->SetWindowSize(width, height);

	wxGLCanvas::OnSize(event);
}

void vtGLCanvas::OnChar(wxKeyEvent& event)
{
	long key = event.KeyCode();

	// pass the char to the frame for it to do "accelerator" shortcuts
	vtFrame *frame = (vtFrame*) GetParent();
	frame->OnChar(event);

	int flags = 0;

	if (event.ControlDown())
		flags |= VT_CONTROL;

	if (event.ShiftDown())
		flags |= VT_SHIFT;

	if (event.AltDown())
		flags |= VT_ALT;

	// pass the char to the vtlib Scene
	vtGetScene()->OnKey(key, flags);
}

void vtGLCanvas::OnMouseEvent(wxMouseEvent& event1)
{
	// turn WX mouse event into a VT mouse event
	vtMouseEvent event;
	wxEventType  ev = event1.GetEventType();
	if (ev == wxEVT_LEFT_DOWN) {
		event.type = VT_DOWN;
		event.button = VT_LEFT;
	} else if (ev == wxEVT_LEFT_UP) {
		event.type = VT_UP;
		event.button = VT_LEFT;
	} else if (ev == wxEVT_MIDDLE_DOWN) {
		event.type = VT_DOWN;
		event.button = VT_MIDDLE;
	} else if (ev == wxEVT_MIDDLE_UP) {
		event.type = VT_UP;
		event.button = VT_MIDDLE;
	} else if (ev == wxEVT_RIGHT_DOWN) {
		event.type = VT_DOWN;
		event.button = VT_RIGHT;
	} else if (ev == wxEVT_RIGHT_UP) {
		event.type = VT_UP;
		event.button = VT_RIGHT;
	} else if (ev == wxEVT_MOTION) {
		event.type = VT_MOVE;
		event.button = VT_NONE;
	} else {
		// ignored mouse events, such as wxEVT_LEAVE_WINDOW
		return;
	}

	if (ev == wxEVT_LEFT_DOWN || ev == wxEVT_MIDDLE_DOWN || ev == wxEVT_RIGHT_DOWN)
		CaptureMouse();
	if (ev == wxEVT_LEFT_UP || ev == wxEVT_MIDDLE_UP || ev == wxEVT_RIGHT_UP)
		ReleaseMouse();

	event.flags = 0;
	wxCoord xpos, ypos;
    event1.GetPosition(&xpos, &ypos);
	event.pos.Set(xpos, ypos);

	if (event1.ControlDown())
		event.flags |= VT_CONTROL;

	if (event1.ShiftDown())
		event.flags |= VT_SHIFT;

	if (event1.AltDown())
		event.flags |= VT_ALT;

	// inform Enviro app
	g_App.OnMouse(event);

	vtGetScene()->OnMouse(event);
}

void vtGLCanvas::OnEraseBackground(wxEraseEvent& event)
{
	// Do nothing, to avoid flashing.
}

<commit_msg>set significant digits of framerate shown to 3 show time only if time is on<commit_after>//
// Name:	 canvas.cpp
// Purpose:	 Implements the canvas class for the wxWindows application.
//
// Copyright (c) 2001 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "vtlib/vtlib.h"
#include "vtlib/core/TimeEngines.h"
#include "vtlib/core/TerrainScene.h"
#include "../Enviro.h"			// for g_App, GetTerrainScene
#include "canvas.h"
#include "frame.h"
#include "app.h"

DECLARE_APP(vtApp)

/*
 * vtGLCanvas implementation
 */
BEGIN_EVENT_TABLE(vtGLCanvas, wxGLCanvas)
	EVT_CLOSE(vtGLCanvas::OnClose)
	EVT_SIZE(vtGLCanvas::OnSize)
	EVT_PAINT(vtGLCanvas::OnPaint)
	EVT_CHAR(vtGLCanvas::OnChar)
	EVT_MOUSE_EVENTS(vtGLCanvas::OnMouseEvent)
	EVT_ERASE_BACKGROUND(vtGLCanvas::OnEraseBackground)
END_EVENT_TABLE()

static vtGLCanvas *s_canvas = NULL;

vtGLCanvas::vtGLCanvas(wxWindow *parent, wxWindowID id,
	const wxPoint& pos, const wxSize& size, long style, const wxString& name, int* gl_attrib):
  wxGLCanvas(parent, id, pos, size, style, name, gl_attrib)
{
	parent->Show(TRUE);
	SetCurrent();

	m_StatusTimer.SetFrame((wxFrame *)parent);
	m_StatusTimer.Start(1000);

	m_bPainting = false;
	m_bRunning = true;
	m_bShowFrameRateChart = true;

	s_canvas = this;
}

vtGLCanvas::~vtGLCanvas(void)
{
}

void EnableContinuousRendering(bool bTrue)
{
	if (s_canvas)
		s_canvas->m_bRunning = bTrue;
}

void vtGLCanvas::QueueRefresh(bool eraseBackground)
	// A Refresh routine we can call from inside OnPaint.
	//   (queues the events rather than dispatching them immediately).
{
	// With wxGTK, you can't do a Refresh() in OnPaint because it doesn't
	//   queue (post) a Refresh event for later.  Rather it dispatches
	//   (processes) the underlying events immediately via ProcessEvent
	//   (read, recursive call).  See the wxPostEvent docs and Refresh code
	//   for more details.
	if ( eraseBackground )
	{
		wxEraseEvent eevent( GetId() );
		eevent.SetEventObject( this );
		wxPostEvent( GetEventHandler(), eevent );
	}

	wxPaintEvent event( GetId() );
	event.SetEventObject( this );
	wxPostEvent( GetEventHandler(), event );
}

void StatusTimer::Notify()
{
	if (!m_pFrame || !m_pFrame->GetStatusBar()) return;

	vtScene *scene = vtGetScene();
	if (!scene) return;

	vtString str, str2;

	// get framerate
	float fps = scene->GetFrameRate();

	// only show 3 significant digits
	if (fps < 10)
		str.Format("fps %1.2f, ", fps);
	else if (fps < 80)
		str.Format("fps %2.1f, ", fps);
	else
		str.Format("fps %3.0f, ", fps);

	// get time of day
	TimeEngine *te = GetTerrainScene()->m_pTime;
	if (te->GetEnabled())
	{
		int hr, min, sec;
		te->GetTime(hr, min, sec);

		str2.Format("time %02d:%02d:%02d, ", hr, min, sec);
		str += str2;
	}

	g_App.DescribeCoordinates(str2);
	str += str2;

	// get CLOD triangle counts, if appropriate
	g_App.DescribeCLOD(str2);
	str += str2;

	str += g_App.m_strMessage;

	m_pFrame->SetStatusText((const char *)str);
}

void vtGLCanvas::OnPaint( wxPaintEvent& event )
{
	// place the dc inside a scope, to delete it before the end of function
	if (1)
	{
		// This is a dummy, to avoid an endless succession of paint messages.
		// OnPaint handlers must always create a wxPaintDC.
		wxPaintDC dc(this);
#ifdef __WXMSW__
		if (!GetContext()) return;
#endif

		if (m_bPainting || !m_bRunning) return;

		m_bPainting = true;

		// Render the Scene Graph
		vtGetScene()->DoUpdate();

		if (m_bShowFrameRateChart)
			vtGetScene()->DrawFrameRateChart();

		SwapBuffers();

#ifdef WIN32
		// Call Refresh again for continuous rendering,
		if (m_bRunning)
			Refresh(FALSE);
#else
		// Queue another refresh for continuous rendering.
		//   (Yield first so we don't starve out keyboard & mouse events.)
		//
		// FIXME: We may want to use a frame timer instead of immediate-
		//   redraw so we don't eat so much CPU on machines that can
		//   easily handle the frame rate.
		wxYield();
		QueueRefresh(FALSE);
#endif

		// update the status bar every 1/10 of a second
		static float last_stat = 0.0f;
		float cur = vtGetTime();
		if (cur - last_stat > 0.1f)
		{
			last_stat = cur;
			m_StatusTimer.Notify();
		}

		m_bPainting = false;
	}

	// Must allow some idle processing to occur - or the toolbars will not
	// update, and the close box will not respond!
	wxGetApp().ProcessIdle();
}

void vtGLCanvas::OnClose(wxCloseEvent& event)
{
	m_bRunning = false;
}

void vtGLCanvas::OnSize(wxSizeEvent& event)
{
  // Presumably this is a wxMSWism.
  // For wxGTK & wxMotif, all canvas resize events occur before the context
  //   is set.  So ignore this context check and grab the window width/height
  //   when we get it so it (and derived values such as aspect ratio and
  //   viewport parms) are computed correctly.
#ifdef __WXMSW__
	if (!GetContext()) return;
#endif

	SetCurrent();
	int width, height;
	GetClientSize(& width, & height);

	vtGetScene()->SetWindowSize(width, height);

	wxGLCanvas::OnSize(event);
}

void vtGLCanvas::OnChar(wxKeyEvent& event)
{
	long key = event.KeyCode();

	// pass the char to the frame for it to do "accelerator" shortcuts
	vtFrame *frame = (vtFrame*) GetParent();
	frame->OnChar(event);

	int flags = 0;

	if (event.ControlDown())
		flags |= VT_CONTROL;

	if (event.ShiftDown())
		flags |= VT_SHIFT;

	if (event.AltDown())
		flags |= VT_ALT;

	// pass the char to the vtlib Scene
	vtGetScene()->OnKey(key, flags);
}

void vtGLCanvas::OnMouseEvent(wxMouseEvent& event1)
{
	// turn WX mouse event into a VT mouse event
	vtMouseEvent event;
	wxEventType  ev = event1.GetEventType();
	if (ev == wxEVT_LEFT_DOWN) {
		event.type = VT_DOWN;
		event.button = VT_LEFT;
	} else if (ev == wxEVT_LEFT_UP) {
		event.type = VT_UP;
		event.button = VT_LEFT;
	} else if (ev == wxEVT_MIDDLE_DOWN) {
		event.type = VT_DOWN;
		event.button = VT_MIDDLE;
	} else if (ev == wxEVT_MIDDLE_UP) {
		event.type = VT_UP;
		event.button = VT_MIDDLE;
	} else if (ev == wxEVT_RIGHT_DOWN) {
		event.type = VT_DOWN;
		event.button = VT_RIGHT;
	} else if (ev == wxEVT_RIGHT_UP) {
		event.type = VT_UP;
		event.button = VT_RIGHT;
	} else if (ev == wxEVT_MOTION) {
		event.type = VT_MOVE;
		event.button = VT_NONE;
	} else {
		// ignored mouse events, such as wxEVT_LEAVE_WINDOW
		return;
	}

	if (ev == wxEVT_LEFT_DOWN || ev == wxEVT_MIDDLE_DOWN || ev == wxEVT_RIGHT_DOWN)
		CaptureMouse();
	if (ev == wxEVT_LEFT_UP || ev == wxEVT_MIDDLE_UP || ev == wxEVT_RIGHT_UP)
		ReleaseMouse();

	event.flags = 0;
	wxCoord xpos, ypos;
    event1.GetPosition(&xpos, &ypos);
	event.pos.Set(xpos, ypos);

	if (event1.ControlDown())
		event.flags |= VT_CONTROL;

	if (event1.ShiftDown())
		event.flags |= VT_SHIFT;

	if (event1.AltDown())
		event.flags |= VT_ALT;

	// inform Enviro app
	g_App.OnMouse(event);

	vtGetScene()->OnMouse(event);
}

void vtGLCanvas::OnEraseBackground(wxEraseEvent& event)
{
	// Do nothing, to avoid flashing.
}

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

// this file defines the otbCommonTest for the test driver
// and all it expects is that you have a function called RegisterTests
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include <iostream>
#include "otbTestMain.h"

void RegisterTests()
{
REGISTER_TEST(otbRADImageIOTestCanRead);
REGISTER_TEST(otbALOSImageIOTestCanRead);
REGISTER_TEST(otbImageFileReaderTest);
}
<commit_msg>BUG. ALOS data aren t yet coded<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

// this file defines the otbCommonTest for the test driver
// and all it expects is that you have a function called RegisterTests
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include <iostream>
#include "otbTestMain.h"

void RegisterTests()
{
REGISTER_TEST(otbRADImageIOTestCanRead);
//REGISTER_TEST(otbALOSImageIOTestCanRead);
REGISTER_TEST(otbImageFileReaderTest);
}
<|endoftext|>


<commit_before>#include "UaParser.h"

#include <cassert>
#include <fstream>
#include <string>
#include <vector>
#include <map>

#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <yaml-cpp/yaml.h>

namespace {

typedef std::map<std::string::size_type, size_t> i2tuple;

struct GenericStore {
  std::string replacement;
  i2tuple replacementMap;
  boost::regex regExpr;
};

struct DeviceStore : GenericStore {
  std::string brandReplacement;
  std::string modelReplacement;
  i2tuple brandReplacementMap;
  i2tuple modelReplacementMap;
};

struct AgentStore : GenericStore {
  std::string majorVersionReplacement;
  std::string minorVersionReplacement;
  std::string patchVersionReplacement;
  std::string patchMinorVersionReplacement;
};

void mark_placeholders(i2tuple& replacement_map, const std::string& device_property) {
  auto loc = device_property.rfind("$");
  while (loc != std::string::npos) {
    replacement_map[loc] = std::stoi(device_property.substr(loc + 1, 1));

    if (loc < 2)
      break;

    loc = device_property.rfind("$", loc - 2);
  }
  return;
}

AgentStore fill_agent_store(const YAML::Node& node,
                            const std::string& repl,
                            const std::string& major_repl,
                            const std::string& minor_repl,
                            const std::string& patch_repl) {
  AgentStore agent_store;
  assert(node.Type() == YAML::NodeType::Map);
  for (auto it = node.begin(); it != node.end(); ++it) {
    const auto key = it->first.as<std::string>();
    const auto value = it->second.as<std::string>();
    if (key == "regex") {
      agent_store.regExpr.assign(value, boost::regex::optimize | boost::regex::normal);
    } else if (key == repl) {
      agent_store.replacement = value;
      mark_placeholders(agent_store.replacementMap, agent_store.replacement);
    } else if (key == major_repl && !value.empty()) {
      agent_store.majorVersionReplacement = value;
    } else if (key == minor_repl && !value.empty()) {
      agent_store.minorVersionReplacement = value;
    } else if (key == patch_repl && !value.empty()) {
      agent_store.patchVersionReplacement = value;
    } else {
      assert(false);
    }
  }
  return agent_store;
}

struct UAStore {
  explicit UAStore(const std::string& regexes_file_path) {
    auto regexes = YAML::LoadFile(regexes_file_path);

    const auto& user_agent_parsers = regexes["user_agent_parsers"];
    for (const auto& user_agent : user_agent_parsers) {
      const auto browser =
          fill_agent_store(user_agent, "family_replacement", "v1_replacement", "v2_replacement", "v3_replacement");
      browserStore.push_back(browser);
    }

    const auto& os_parsers = regexes["os_parsers"];
    for (const auto& o : os_parsers) {
      const auto os =
          fill_agent_store(o, "os_replacement", "os_v1_replacement", "os_v2_replacement", "os_v3_replacement");
      osStore.push_back(os);
    }

    const auto& device_parsers = regexes["device_parsers"];
    for (const auto& d : device_parsers) {
      DeviceStore device;
      bool regex_flag = false;
      for (auto it = d.begin(); it != d.end(); ++it) {
        const auto key = it->first.as<std::string>();
        const auto value = it->second.as<std::string>();
        if (key == "regex") {
          device.regExpr.assign(value, boost::regex::optimize | boost::regex::normal);
        } else if (key == "regex_flag" && value == "i") {
          regex_flag = true;
        } else if (key == "device_replacement") {
          device.replacement = value;
          mark_placeholders(device.replacementMap, device.replacement);
        } else if (key == "model_replacement") {
          device.modelReplacement = value;
          mark_placeholders(device.modelReplacementMap, device.modelReplacement);
        } else if (key == "brand_replacement") {
          device.brandReplacement = value;
          mark_placeholders(device.brandReplacementMap, device.brandReplacement);
        } else {
          assert(false);
        }
      }
      if (regex_flag == true) {
        device.regExpr.assign(device.regExpr.str(),
                              boost::regex::optimize | boost::regex::icase | boost::regex::normal);
      }
      deviceStore.push_back(device);
    }
  }

  std::vector<DeviceStore> deviceStore;
  std::vector<AgentStore> osStore;
  std::vector<AgentStore> browserStore;
};

template <class AGENT, class AGENT_STORE>
void fill_agent(AGENT& agent, const AGENT_STORE& store, const boost::smatch& m, const bool os) {
  if (m.size() > 1) {
    agent.family =
        !store.replacement.empty() ? boost::regex_replace(store.replacement, boost::regex("\\$1"), m[1].str()) : m[1];
  } else {
    agent.family =
        !store.replacement.empty() ? boost::regex_replace(store.replacement, boost::regex("\\$1"), m[0].str()) : m[0];
  }
  boost::algorithm::trim(agent.family);

  // The chunk above is slightly faster than the one below.
  // if ( store.replacement.empty() && m.size() > 1) {
  //   agent.family = m[1].str();
  // } else {
  //     agent.family = store.replacement;
  //     if ( ! store.replacementMap.empty()) {
  //       replace_all_placeholders(agent.family,m,store.replacementMap);
  //     }
  // }

  if (!store.majorVersionReplacement.empty()) {
    agent.major = store.majorVersionReplacement;
  } else if (m.size() > 2) {
    agent.major = m[2].str();
  }
  if (!store.minorVersionReplacement.empty()) {
    agent.minor = store.minorVersionReplacement;
  } else if (m.size() > 3) {
    agent.minor = m[3].str();
  }
  if (!store.patchVersionReplacement.empty()) {
    agent.patch = store.patchVersionReplacement;
  } else if (m.size() > 4) {
    agent.patch = m[4].str();
  }
  if (os && m.size() > 5) {
    agent.patch_minor = m[5].str();
  }
}

/////////////
// HELPERS //
/////////////

void replace_all_placeholders(std::string& ua_property, const boost::smatch& result, const i2tuple& replacement_map) {
  for (auto iter = replacement_map.rbegin(); iter != replacement_map.rend(); ++iter) {
    ua_property.replace(iter->first, 2, result[iter->second].str());
  }
  boost::algorithm::trim(ua_property);
  return;
}

UserAgent parse_impl(const std::string& ua, const UAStore* ua_store) {
  UserAgent uagent;

  for (const auto& b : ua_store->browserStore) {
    auto& browser = uagent.browser;
    boost::smatch m;
    if (boost::regex_search(ua, m, b.regExpr)) {
      fill_agent(browser, b, m, false);
      break;
    } else {
      browser.family = "Other";
    }
  }

  for (const auto& o : ua_store->osStore) {
    auto& os = uagent.os;
    boost::smatch m;
    if (boost::regex_search(ua, m, o.regExpr)) {
      fill_agent(os, o, m, true);
      break;
    } else {
      os.family = "Other";
    }
  }

  for (const auto& d : ua_store->deviceStore) {
    auto& device = uagent.device;
    boost::smatch m;

    if (boost::regex_search(ua, m, d.regExpr)) {
      if (d.replacement.empty() && m.size() > 1) {
        device.family = m[1].str();
      } else {
        device.family = d.replacement;
        if (!d.replacementMap.empty()) {
          replace_all_placeholders(device.family, m, d.replacementMap);
        }
      }

      if (!d.brandReplacement.empty()) {
        device.brand = d.brandReplacement;
        if (!d.brandReplacementMap.empty()) {
          replace_all_placeholders(device.brand, m, d.brandReplacementMap);
        }
      }
      if (d.modelReplacement.empty() && m.size() > 1) {
        device.model = m[1].str();
      } else {
        device.model = d.modelReplacement;
        if (!d.modelReplacementMap.empty()) {
          replace_all_placeholders(device.model, m, d.modelReplacementMap);
        }
      }
      break;
    } else {
      device.family = "Other";
    }
  }
  return uagent;
}

}  // namespace

UserAgentParser::UserAgentParser(const std::string& regexes_file_path) : regexes_file_path_{regexes_file_path} {
  ua_store_ = new UAStore(regexes_file_path);
}

UserAgentParser::~UserAgentParser() {
  delete static_cast<const UAStore*>(ua_store_);
}

UserAgent UserAgentParser::parse(const std::string& ua) const {
  return parse_impl(ua, static_cast<const UAStore*>(ua_store_));
}
<commit_msg>Split parse_impl<commit_after>#include "UaParser.h"

#include <cassert>
#include <fstream>
#include <string>
#include <vector>
#include <map>

#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <yaml-cpp/yaml.h>

namespace {

typedef std::map<std::string::size_type, size_t> i2tuple;

struct GenericStore {
  std::string replacement;
  i2tuple replacementMap;
  boost::regex regExpr;
};

struct DeviceStore : GenericStore {
  std::string brandReplacement;
  std::string modelReplacement;
  i2tuple brandReplacementMap;
  i2tuple modelReplacementMap;
};

struct AgentStore : GenericStore {
  std::string majorVersionReplacement;
  std::string minorVersionReplacement;
  std::string patchVersionReplacement;
  std::string patchMinorVersionReplacement;
};

void mark_placeholders(i2tuple& replacement_map, const std::string& device_property) {
  auto loc = device_property.rfind("$");
  while (loc != std::string::npos) {
    replacement_map[loc] = std::stoi(device_property.substr(loc + 1, 1));

    if (loc < 2)
      break;

    loc = device_property.rfind("$", loc - 2);
  }
  return;
}

AgentStore fill_agent_store(const YAML::Node& node,
                            const std::string& repl,
                            const std::string& major_repl,
                            const std::string& minor_repl,
                            const std::string& patch_repl) {
  AgentStore agent_store;
  assert(node.Type() == YAML::NodeType::Map);
  for (auto it = node.begin(); it != node.end(); ++it) {
    const auto key = it->first.as<std::string>();
    const auto value = it->second.as<std::string>();
    if (key == "regex") {
      agent_store.regExpr.assign(value, boost::regex::optimize | boost::regex::normal);
    } else if (key == repl) {
      agent_store.replacement = value;
      mark_placeholders(agent_store.replacementMap, agent_store.replacement);
    } else if (key == major_repl && !value.empty()) {
      agent_store.majorVersionReplacement = value;
    } else if (key == minor_repl && !value.empty()) {
      agent_store.minorVersionReplacement = value;
    } else if (key == patch_repl && !value.empty()) {
      agent_store.patchVersionReplacement = value;
    } else {
      assert(false);
    }
  }
  return agent_store;
}

struct UAStore {
  explicit UAStore(const std::string& regexes_file_path) {
    auto regexes = YAML::LoadFile(regexes_file_path);

    const auto& user_agent_parsers = regexes["user_agent_parsers"];
    for (const auto& user_agent : user_agent_parsers) {
      const auto browser =
          fill_agent_store(user_agent, "family_replacement", "v1_replacement", "v2_replacement", "v3_replacement");
      browserStore.push_back(browser);
    }

    const auto& os_parsers = regexes["os_parsers"];
    for (const auto& o : os_parsers) {
      const auto os =
          fill_agent_store(o, "os_replacement", "os_v1_replacement", "os_v2_replacement", "os_v3_replacement");
      osStore.push_back(os);
    }

    const auto& device_parsers = regexes["device_parsers"];
    for (const auto& d : device_parsers) {
      DeviceStore device;
      bool regex_flag = false;
      for (auto it = d.begin(); it != d.end(); ++it) {
        const auto key = it->first.as<std::string>();
        const auto value = it->second.as<std::string>();
        if (key == "regex") {
          device.regExpr.assign(value, boost::regex::optimize | boost::regex::normal);
        } else if (key == "regex_flag" && value == "i") {
          regex_flag = true;
        } else if (key == "device_replacement") {
          device.replacement = value;
          mark_placeholders(device.replacementMap, device.replacement);
        } else if (key == "model_replacement") {
          device.modelReplacement = value;
          mark_placeholders(device.modelReplacementMap, device.modelReplacement);
        } else if (key == "brand_replacement") {
          device.brandReplacement = value;
          mark_placeholders(device.brandReplacementMap, device.brandReplacement);
        } else {
          assert(false);
        }
      }
      if (regex_flag == true) {
        device.regExpr.assign(device.regExpr.str(),
                              boost::regex::optimize | boost::regex::icase | boost::regex::normal);
      }
      deviceStore.push_back(device);
    }
  }

  std::vector<DeviceStore> deviceStore;
  std::vector<AgentStore> osStore;
  std::vector<AgentStore> browserStore;
};

template <class AGENT, class AGENT_STORE>
void fill_agent(AGENT& agent, const AGENT_STORE& store, const boost::smatch& m, const bool os) {
  if (m.size() > 1) {
    agent.family =
        !store.replacement.empty() ? boost::regex_replace(store.replacement, boost::regex("\\$1"), m[1].str()) : m[1];
  } else {
    agent.family =
        !store.replacement.empty() ? boost::regex_replace(store.replacement, boost::regex("\\$1"), m[0].str()) : m[0];
  }
  boost::algorithm::trim(agent.family);

  // The chunk above is slightly faster than the one below.
  // if ( store.replacement.empty() && m.size() > 1) {
  //   agent.family = m[1].str();
  // } else {
  //     agent.family = store.replacement;
  //     if ( ! store.replacementMap.empty()) {
  //       replace_all_placeholders(agent.family,m,store.replacementMap);
  //     }
  // }

  if (!store.majorVersionReplacement.empty()) {
    agent.major = store.majorVersionReplacement;
  } else if (m.size() > 2) {
    agent.major = m[2].str();
  }
  if (!store.minorVersionReplacement.empty()) {
    agent.minor = store.minorVersionReplacement;
  } else if (m.size() > 3) {
    agent.minor = m[3].str();
  }
  if (!store.patchVersionReplacement.empty()) {
    agent.patch = store.patchVersionReplacement;
  } else if (m.size() > 4) {
    agent.patch = m[4].str();
  }
  if (os && m.size() > 5) {
    agent.patch_minor = m[5].str();
  }
}

/////////////
// HELPERS //
/////////////

void replace_all_placeholders(std::string& ua_property, const boost::smatch& result, const i2tuple& replacement_map) {
  for (auto iter = replacement_map.rbegin(); iter != replacement_map.rend(); ++iter) {
    ua_property.replace(iter->first, 2, result[iter->second].str());
  }
  boost::algorithm::trim(ua_property);
  return;
}

Device parse_device_impl(const std::string& ua, const UAStore* ua_store) {
  Device device;

  for (const auto& d : ua_store->deviceStore) {
    boost::smatch m;

    if (boost::regex_search(ua, m, d.regExpr)) {
      if (d.replacement.empty() && m.size() > 1) {
        device.family = m[1].str();
      } else {
        device.family = d.replacement;
        if (!d.replacementMap.empty()) {
          replace_all_placeholders(device.family, m, d.replacementMap);
        }
      }

      if (!d.brandReplacement.empty()) {
        device.brand = d.brandReplacement;
        if (!d.brandReplacementMap.empty()) {
          replace_all_placeholders(device.brand, m, d.brandReplacementMap);
        }
      }
      if (d.modelReplacement.empty() && m.size() > 1) {
        device.model = m[1].str();
      } else {
        device.model = d.modelReplacement;
        if (!d.modelReplacementMap.empty()) {
          replace_all_placeholders(device.model, m, d.modelReplacementMap);
        }
      }
      break;
    } else {
      device.family = "Other";
    }
  }

  return device;
}

Agent parse_browser_impl(const std::string& ua, const UAStore* ua_store) {
  Agent browser;

  for (const auto& b : ua_store->browserStore) {
    boost::smatch m;
    if (boost::regex_search(ua, m, b.regExpr)) {
      fill_agent(browser, b, m, false);
      break;
    } else {
      browser.family = "Other";
    }
  }

  return browser;
}

Agent parse_os_impl(const std::string& ua, const UAStore* ua_store) {
  Agent os;

  for (const auto& o : ua_store->osStore) {
    boost::smatch m;
    if (boost::regex_search(ua, m, o.regExpr)) {
      fill_agent(os, o, m, true);
      break;
    } else {
      os.family = "Other";
    }
  }

  return os;
}

}  // namespace

UserAgentParser::UserAgentParser(const std::string& regexes_file_path) : regexes_file_path_{regexes_file_path} {
  ua_store_ = new UAStore(regexes_file_path);
}

UserAgentParser::~UserAgentParser() {
  delete static_cast<const UAStore*>(ua_store_);
}

UserAgent UserAgentParser::parse(const std::string& ua) const {
  const auto ua_store = static_cast<const UAStore*>(ua_store_);

  const auto device = parse_device_impl(ua, ua_store);
  const auto os = parse_os_impl(ua, ua_store);
  const auto browser = parse_browser_impl(ua, ua_store);

  return {device, os, browser};
}
<|endoftext|>


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

#include <windows.h>
#include <immdev.h>
#include <new>
#include "Resource.h"
#include "Globals.h"
#include "InputContext.h"
#include "CompString.h"
#include "UiWindow.h"

namespace /* unnamed */
{
    inline HIMC getImc(HWND hWnd)
    {
        return reinterpret_cast<HIMC>(GetWindowLongPtr(hWnd, IMMGWLP_IMC));
    }

    inline UiWindow* getUiWindowObject(HWND hWnd)
    {
        return reinterpret_cast<UiWindow*>(GetWindowLongPtr(hWnd, IMMGWLP_PRIVATE));
    }

    inline void setUiWindowObject(HWND hWnd, UiWindow* uiWnd)
    {
        SetWindowLongPtr(hWnd, IMMGWLP_PRIVATE, reinterpret_cast<LONG_PTR>(uiWnd));
    }

} // unnamed namespace

UiWindow::UiWindow()
{
}

UiWindow::~UiWindow()
{
}

LRESULT UiWindow::imeSetContext(HWND wnd, WPARAM activate, LPARAM iscBits)
{
    if (activate) {
        InputContext imc(getImc(wnd));

        if (imc.lock()) {
            if (iscBits & ISC_SHOWUICOMPOSITIONWINDOW) {
                CompString cs(imc);
                if (cs.lock() && cs.compStr.size() != 0) {
                    compWnd.create(wnd);
                    compWnd.update();
                    compWnd.show();
                }
            }
            if (iscBits & ISC_SHOWUIGUIDELINE) {
                // TODO
            }
        }
    } else {
        if (iscBits & ISC_SHOWUICOMPOSITIONWINDOW) {
            if (compWnd.isOn()) {
                compWnd.hide();
            }
        }
        if (iscBits & ISC_SHOWUIGUIDELINE) {
            // TODO
        }
    }

    return 0;
}

LRESULT UiWindow::imeControl(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    InputContext imc(getImc(wnd));

    switch (wParam) {
    case IMC_GETCOMPOSITIONWINDOW:
        if (imc.lock()) {
            *(COMPOSITIONFORM*)lParam = imc->cfCompForm;
            return 0;
        }
        return 1;

    default:
        return 1;
    }
}

void UiWindow::imeSelect(HWND wnd, WPARAM wParam, LPARAM lParam)
{
}

void UiWindow::imeNotify(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    InputContext imc(getImc(wnd));

    switch (wParam) {
    case IMN_SETOPENSTATUS:
        // TODO
        break;
    case IMN_SETCOMPOSITIONFONT:
        if (imc.lock()) {
            compWnd.setFont((LOGFONT*)&imc->lfFont);
            if (compWnd.isOn())
                compWnd.update();
        }
        break;
    case IMN_SETCOMPOSITIONWINDOW:
        if (compWnd.isOn())
            compWnd.update();
        break;
    case IMN_GUIDELINE:
        // TODO
        break;

    // No private notification messages yet
    case IMN_PRIVATE:
        break;

    // What should I do with these?
    case IMN_SETCONVERSIONMODE:
    case IMN_SETSENTENCEMODE:
        break;

    // We don't have a candidate window
    case IMN_CHANGECANDIDATE:
    case IMN_OPENCANDIDATE:
    case IMN_CLOSECANDIDATE:
    case IMN_SETCANDIDATEPOS:
        break;

    // We don't have a status window
    case IMN_CLOSESTATUSWINDOW:
    case IMN_OPENSTATUSWINDOW:
    case IMN_SETSTATUSWINDOWPOS:
        break;

    // We don't have a soft keyboard
    case IMN_SOFTKBDDESTROYED:
        break;
    }
}

void UiWindow::imeStartComposition(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    compWnd.create(wnd);
}

void UiWindow::imeComposition(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    if (compWnd.isOn()) {
        compWnd.update();
        compWnd.show();
    }
}

void UiWindow::imeEndComposition(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    if (compWnd.isOn())
        compWnd.hide();
}

LRESULT CALLBACK UiWindow::windowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    UiWindow* uiWnd;

    switch (msg) {
    case WM_IME_SETCONTEXT:
    case WM_IME_CONTROL:
    case WM_IME_SELECT:
    case WM_IME_NOTIFY:
    case WM_IME_STARTCOMPOSITION:
    case WM_IME_COMPOSITION:
    case WM_IME_ENDCOMPOSITION:
    case WM_IME_COMPOSITIONFULL:
        uiWnd = getUiWindowObject(wnd);
        if (!uiWnd)
            return 0;
        break;
    }

    switch (msg) {
    case WM_CREATE:
        setUiWindowObject(wnd, new UiWindow());
        return 0;

    case WM_DESTROY:
        delete getUiWindowObject(wnd);
        return 0;

    case WM_IME_SETCONTEXT:
        return uiWnd->imeSetContext(wnd, wParam, lParam);

    case WM_IME_CONTROL:
        return uiWnd->imeControl(wnd, wParam, lParam);

    case WM_IME_SELECT:
        uiWnd->imeSelect(wnd, wParam, lParam);
        return 0;

    case WM_IME_NOTIFY:
        uiWnd->imeNotify(wnd, wParam, lParam);
        return 0;

    case WM_IME_STARTCOMPOSITION:
        uiWnd->imeStartComposition(wnd, wParam, lParam);
        return 0;

    case WM_IME_COMPOSITION:
        uiWnd->imeComposition(wnd, wParam, lParam);
        return 0;

    case WM_IME_ENDCOMPOSITION:
        uiWnd->imeEndComposition(wnd, wParam, lParam);
        return 0;

    case WM_IME_COMPOSITIONFULL:
        // How did this message get here?!
        return 0;

    default:
        return DefWindowProc(wnd, msg, wParam, lParam);
    }
}

void UiWindow::registerClass()
{
    WNDCLASSEX wcex;

    wcex.cbSize         = sizeof(WNDCLASSEX);
    wcex.style          = CS_IME;
    wcex.lpfnWndProc    = windowProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = sizeof(LONG_PTR) * 2;
    wcex.hInstance      = moduleInstance;
    wcex.hIcon          = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = NULL;
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = uiClassName;
    wcex.hIconSm        = NULL;

    RegisterClassEx(&wcex);
}

void UiWindow::unregisterClass()
{
    UnregisterClass(uiClassName, moduleInstance);
}
<commit_msg>Some code cleanup.<commit_after>/*
 * Copyright 2009 Odbayar Nyamtseren <odbayar.n@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <windows.h>
#include <immdev.h>
#include <new>
#include "Resource.h"
#include "Globals.h"
#include "InputContext.h"
#include "CompString.h"
#include "UiWindow.h"

namespace /* unnamed */
{
    inline HIMC getImc(HWND hWnd)
    {
        return reinterpret_cast<HIMC>(GetWindowLongPtr(hWnd, IMMGWLP_IMC));
    }

    inline UiWindow* getUiWindowObject(HWND hWnd)
    {
        return reinterpret_cast<UiWindow*>(GetWindowLongPtr(hWnd, IMMGWLP_PRIVATE));
    }

    inline void setUiWindowObject(HWND hWnd, UiWindow* uiWnd)
    {
        SetWindowLongPtr(hWnd, IMMGWLP_PRIVATE, reinterpret_cast<LONG_PTR>(uiWnd));
    }

} // unnamed namespace

UiWindow::UiWindow()
{
}

UiWindow::~UiWindow()
{
}

LRESULT UiWindow::imeSetContext(HWND wnd, WPARAM activate, LPARAM iscBits)
{
    if (activate) {
        InputContext imc(getImc(wnd));

        if (imc.lock()) {
            if (iscBits & ISC_SHOWUICOMPOSITIONWINDOW) {
                CompString cs(imc);
                if (cs.lock() && cs.compStr.size() != 0) {
                    compWnd.create(wnd);
                    compWnd.update();
                    compWnd.show();
                }
            }
        }
    } else {
        if (iscBits & ISC_SHOWUICOMPOSITIONWINDOW) {
            if (compWnd.isOn()) {
                compWnd.hide();
            }
        }
    }

    return 0;
}

LRESULT UiWindow::imeControl(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    InputContext imc(getImc(wnd));
    LRESULT retValue = 1;

    switch (wParam) {
    case IMC_GETCOMPOSITIONWINDOW:
        if (imc.lock()) {
            *(COMPOSITIONFORM*)lParam = imc->cfCompForm;
            retValue = 0;
        }
        break;
    }

    return retValue;
}

void UiWindow::imeSelect(HWND wnd, WPARAM wParam, LPARAM lParam)
{
}

void UiWindow::imeNotify(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    InputContext imc(getImc(wnd));

    switch (wParam) {
    case IMN_SETOPENSTATUS:
        // TODO
        break;
    case IMN_SETCOMPOSITIONFONT:
        if (imc.lock()) {
            compWnd.setFont((LOGFONT*)&imc->lfFont);
            if (compWnd.isOn())
                compWnd.update();
        }
        break;
    case IMN_SETCOMPOSITIONWINDOW:
        if (compWnd.isOn())
            compWnd.update();
        break;
    case IMN_GUIDELINE:
        // TODO
        break;

    // No private notification messages yet
    case IMN_PRIVATE:
        break;

    // What should I do with these?
    case IMN_SETCONVERSIONMODE:
    case IMN_SETSENTENCEMODE:
        break;

    // We don't have a candidate window
    case IMN_CHANGECANDIDATE:
    case IMN_OPENCANDIDATE:
    case IMN_CLOSECANDIDATE:
    case IMN_SETCANDIDATEPOS:
        break;

    // We don't have a status window
    case IMN_CLOSESTATUSWINDOW:
    case IMN_OPENSTATUSWINDOW:
    case IMN_SETSTATUSWINDOWPOS:
        break;

    // We don't have a soft keyboard
    case IMN_SOFTKBDDESTROYED:
        break;
    }
}

void UiWindow::imeStartComposition(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    compWnd.create(wnd);
}

void UiWindow::imeComposition(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    if (compWnd.isOn()) {
        compWnd.update();
        compWnd.show();
    }
}

void UiWindow::imeEndComposition(HWND wnd, WPARAM wParam, LPARAM lParam)
{
    if (compWnd.isOn())
        compWnd.hide();
}

LRESULT CALLBACK UiWindow::windowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    UiWindow* uiWnd;

    switch (msg) {
    case WM_IME_SETCONTEXT:
    case WM_IME_CONTROL:
    case WM_IME_SELECT:
    case WM_IME_NOTIFY:
    case WM_IME_STARTCOMPOSITION:
    case WM_IME_COMPOSITION:
    case WM_IME_ENDCOMPOSITION:
    case WM_IME_COMPOSITIONFULL:
        uiWnd = getUiWindowObject(wnd);
        if (!uiWnd)
            return 0;
        break;
    }

    switch (msg) {
    case WM_CREATE:
        setUiWindowObject(wnd, new UiWindow());
        return 0;

    case WM_DESTROY:
        delete getUiWindowObject(wnd);
        return 0;

    case WM_IME_SETCONTEXT:
        return uiWnd->imeSetContext(wnd, wParam, lParam);

    case WM_IME_CONTROL:
        return uiWnd->imeControl(wnd, wParam, lParam);

    case WM_IME_SELECT:
        uiWnd->imeSelect(wnd, wParam, lParam);
        return 0;

    case WM_IME_NOTIFY:
        uiWnd->imeNotify(wnd, wParam, lParam);
        return 0;

    case WM_IME_STARTCOMPOSITION:
        uiWnd->imeStartComposition(wnd, wParam, lParam);
        return 0;

    case WM_IME_COMPOSITION:
        uiWnd->imeComposition(wnd, wParam, lParam);
        return 0;

    case WM_IME_ENDCOMPOSITION:
        uiWnd->imeEndComposition(wnd, wParam, lParam);
        return 0;

    case WM_IME_COMPOSITIONFULL:
        // How did this message get here?!
        return 0;

    default:
        return DefWindowProc(wnd, msg, wParam, lParam);
    }
}

void UiWindow::registerClass()
{
    WNDCLASSEX wcex;

    wcex.cbSize         = sizeof(WNDCLASSEX);
    wcex.style          = CS_IME;
    wcex.lpfnWndProc    = windowProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = sizeof(LONG_PTR) * 2;
    wcex.hInstance      = moduleInstance;
    wcex.hIcon          = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = NULL;
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = uiClassName;
    wcex.hIconSm        = NULL;

    RegisterClassEx(&wcex);
}

void UiWindow::unregisterClass()
{
    UnregisterClass(uiClassName, moduleInstance);
}
<|endoftext|>


<commit_before>// Copyright 2016 Headcrash Industries LLC

#include "WindowsMessageHandlerExamplePrivatePCH.h"
#include "ModuleInterface.h"
#include "SlateApplication.h"
#include "WindowsApplication.h"
#include "WindowsMessageHelpers.h"

#define LOCTEXT_NAMESPACE "FWindowsMessageHandlerExampleModule"

/**
 * Example Windows message handler.
 */
class FExampleHandler
	: public IWindowsMessageHandler
{
public:

	// IWindowsMessageHandler interface

	virtual bool ProcessMessage(HWND Hwnd, uint32 Message, WPARAM WParam, LPARAM LParam, int32& OutResult) override
	{
		// log out some details for the received message
		GLog->Logf(TEXT("WindowsMessageHandlerExampleModule: hwnd = %i, msg = %s, wParam = %i, lParam = %i"), Hwnd, *GetMessageName(Message), WParam, LParam);

		// we did not handle this message, so make sure it gets passed on to other handlers
		return false;
	}
};

/**
 * Implements the WindowsMessageHandlerExample module.
 */
class FWindowsMessageHandlerExampleModule
	: public IModuleInterface
{
public:

	// IModuleInterface interface

	virtual void FWindowsMessageHandlerExampleModule::StartupModule() override
	{
		// register our handler
		FWindowsApplication* Application = GetApplication();

		if (Application != nullptr)
		{
			Application->AddMessageHandler(Handler);
		}
	}

	virtual void FWindowsMessageHandlerExampleModule::ShutdownModule() override
	{
		// unregister our handler
		FWindowsApplication* Application = GetApplication();

		if (Application != nullptr)
		{
			Application->RemoveMessageHandler(Handler);
		}
	}

protected:

	FWindowsApplication* GetApplication() const
	{
		if (!FSlateApplication::IsInitialized())
		{
			return nullptr;
		}

		return (FWindowsApplication*)FSlateApplication::Get().GetPlatformApplication().Get();
	}

private:

	FExampleHandler Handler;
};

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(FWindowsMessageHandlerExampleModule, WindowsMessageHandlerExample)
<commit_msg>Added support for 4.11<commit_after>// Copyright 2016 Headcrash Industries LLC

#include "WindowsMessageHandlerExamplePrivatePCH.h"
#include "ModuleInterface.h"
#include "SlateBasics.h"
#include "WindowsApplication.h"
#include "WindowsMessageHelpers.h"

#define LOCTEXT_NAMESPACE "FWindowsMessageHandlerExampleModule"

/**
 * Example Windows message handler.
 */
class FExampleHandler
	: public IWindowsMessageHandler
{
public:

	// IWindowsMessageHandler interface

	virtual bool ProcessMessage(HWND Hwnd, uint32 Message, WPARAM WParam, LPARAM LParam, int32& OutResult) override
	{
		// log out some details for the received message
		GLog->Logf(TEXT("WindowsMessageHandlerExampleModule: hwnd = %i, msg = %s, wParam = %i, lParam = %i"), Hwnd, *GetMessageName(Message), WParam, LParam);

		// we did not handle this message, so make sure it gets passed on to other handlers
		return false;
	}
};

/**
 * Implements the WindowsMessageHandlerExample module.
 */
class FWindowsMessageHandlerExampleModule
	: public IModuleInterface
{
public:

	// IModuleInterface interface

	virtual void FWindowsMessageHandlerExampleModule::StartupModule() override
	{
		// register our handler
		FWindowsApplication* Application = GetApplication();

		if (Application != nullptr)
		{
			Application->AddMessageHandler(Handler);
		}
	}

	virtual void FWindowsMessageHandlerExampleModule::ShutdownModule() override
	{
		// unregister our handler
		FWindowsApplication* Application = GetApplication();

		if (Application != nullptr)
		{
			Application->RemoveMessageHandler(Handler);
		}
	}

protected:

	FWindowsApplication* GetApplication() const
	{
		if (!FSlateApplication::IsInitialized())
		{
			return nullptr;
		}

		return (FWindowsApplication*)FSlateApplication::Get().GetPlatformApplication().Get();
	}

private:

	FExampleHandler Handler;
};

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(FWindowsMessageHandlerExampleModule, WindowsMessageHandlerExample)
<|endoftext|>