<commit_before>/* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of NVIDIA CORPORATION nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <regex>

#include "parser.hpp"
#include "arch-properties.hpp"

namespace mapping
{

//
// Shared state.
//

ArchProperties arch_props_;
problem::Workload workload_;

//
// Forward declarations.
//
unsigned FindTargetTilingLevel(config::CompoundConfigNode constraint, std::string type);
std::map<problem::Shape::DimensionID, int> ParseUserFactors(config::CompoundConfigNode constraint);
std::vector<problem::Shape::DimensionID> ParseUserPermutations(config::CompoundConfigNode constraint);
void ParseUserDatatypeBypassSettings(config::CompoundConfigNode constraint,
                                     unsigned level,
                                     problem::PerDataSpace<std::string>& user_bypass_strings);
//
// Parse mapping in libconfig format and generate data structure.
//
Mapping ParseAndConstruct(config::CompoundConfigNode config,
                          model::Engine::Specs& arch_specs,
                          problem::Workload workload)
{
  arch_props_.Construct(arch_specs);
  workload_ = workload;

  std::map<unsigned, std::map<problem::Shape::DimensionID, int>> user_factors;
  std::map<unsigned, std::vector<problem::Shape::DimensionID>> user_permutations;
  std::map<unsigned, std::uint32_t> user_spatial_splits;
  problem::PerDataSpace<std::string> user_bypass_strings;

  // Initialize user bypass strings to "XXXXX...1" (note the 1 at the end).
  // FIXME: there's probably a cleaner way/place to initialize this.
  for (unsigned pvi = 0; pvi < unsigned(problem::GetShape()->NumDataSpaces); pvi++)
  {
    std::string xxx(arch_props_.StorageLevels(), 'X');
    xxx.back() = '1';
    user_bypass_strings[problem::Shape::DataSpaceID(pvi)] = xxx;
  }

  // Parse user-provided mapping.
  assert(config.isList());

  // Iterate over all the directives.
  int len = config.getLength();
  for (int i = 0; i < len; i ++)
  {
    auto directive = config[i];
    // Find out if this is a temporal directive or a spatial directive.
    std::string type;
    assert(directive.lookupValue("type", type));

    auto level_id = FindTargetTilingLevel(directive, type);

    if (type == "temporal" || type == "spatial")
    {
      auto level_factors = ParseUserFactors(directive);
      if (level_factors.size() > 0)
      {
        user_factors[level_id] = level_factors;
      }

      auto level_permutations = ParseUserPermutations(directive);
      if (level_permutations.size() > 0)
      {
        user_permutations[level_id] = level_permutations;
      }

      if (type == "spatial")
      {
        // Initialize user spatial splits to map all dimensions to the hardware X-axis.
        std::uint32_t user_split = unsigned(problem::GetShape()->NumDimensions);
        directive.lookupValue("split", user_split);
        user_spatial_splits[level_id] = user_split;
      }
    }
    else if (type == "datatype" || type == "bypass")
    {
      ParseUserDatatypeBypassSettings(directive,
                                      arch_props_.TilingToStorage(level_id),
                                      user_bypass_strings);
    }
    else
    {
      assert(false);
    }
  }

  // Validity checks.
  std::map<problem::Shape::DimensionID, int> dimension_factor_products;
  for (unsigned dim = 0; dim < problem::GetShape()->NumDimensions; dim++)
    dimension_factor_products[dim] = 1;

  // Construct the mapping from the parsed sub-structures.
  // A set of subnests, one for each tiling level.
  loop::NestConfig subnests(arch_props_.TilingLevels());

  // Construct num_storage_levels loop-nest partitions and assign factors, dimensions
  // and spatial split points.
  for (uint64_t level = 0; level < arch_props_.TilingLevels(); level++)
  {
    auto permutation = user_permutations.find(level);
    if (permutation == user_permutations.end())
    {
      std::cerr << "ERROR: parsing mapping: permutation not found for level: "
                << arch_props_.TilingLevelName(level) << std::endl;
      exit(1);
    }
    assert(permutation->second.size() == std::size_t(problem::GetShape()->NumDimensions));

    auto factors = user_factors.find(level);
    if (factors == user_factors.end())
    {
      std::cerr << "ERROR: parsing mapping: factors not found for level: "
                << arch_props_.TilingLevelName(level) << std::endl;
      exit(1);
    }
    assert(factors->second.size() == std::size_t(problem::GetShape()->NumDimensions));

    // Each partition has problem::GetShape()->NumDimensions loops.
    for (unsigned idim = 0; idim < unsigned(problem::GetShape()->NumDimensions); idim++)
    {
      loop::Descriptor loop;
      loop.dimension = permutation->second.at(idim);
      loop.start = 0;
      loop.end = factors->second.at(loop.dimension);
      loop.stride = 1; // FIXME.
      loop.spacetime_dimension = arch_props_.IsSpatial(level)
        ? (idim < user_spatial_splits.at(level) ? spacetime::Dimension::SpaceX : spacetime::Dimension::SpaceY)
        : spacetime::Dimension::Time;
      subnests.at(level).push_back(loop);

      dimension_factor_products[loop.dimension] *= loop.end;
    }
  }

  // All user-provided factors must multiply-up to the dimension size.
  bool fault = false;
  for (unsigned dim = 0; dim < problem::GetShape()->NumDimensions; dim++)
  {
    if (dimension_factor_products[dim] != workload_.GetBound(dim))
    {
      std::cerr << "ERROR: parsing mapping: product of all factors of dimension "
                << problem::GetShape()->DimensionIDToName.at(dim) << " is "
                << dimension_factor_products[dim] << ", which is not equal to "
                << "the dimension bound " << workload_.GetBound(dim)
                << std::endl;
      fault = true;
    }
  }
  if (fault)
  {
    exit(1);
  }

  // Concatenate the subnests to form the final mapping nest.
  Mapping mapping;

  std::uint64_t storage_level = 0;
  for (uint64_t i = 0; i < arch_props_.TilingLevels(); i++)
  {
    uint64_t num_subnests_added = 0;
    for (int dim = 0; dim < int(problem::GetShape()->NumDimensions); dim++)
    {
      // Ignore trivial factors
      // This reduces computation time by 1.5x on average.
      if (subnests[i][dim].start + subnests[i][dim].stride < subnests[i][dim].end)
      {
        mapping.loop_nest.AddLoop(subnests[i][dim]);
        num_subnests_added++;
      }
    }
    if (!arch_props_.IsSpatial(i))
    {
      if (num_subnests_added == 0)
      {
        // Add a trivial temporal nest to make sure
        // we have at least one subnest in each level.
        mapping.loop_nest.AddLoop(problem::Shape::DimensionID(int(problem::GetShape()->NumDimensions) - 1),
                                   0, 1, 1, spacetime::Dimension::Time);
      }
      mapping.loop_nest.AddStorageTilingBoundary();
      storage_level++;
    }
  }

  // The user_mask input is a set of per-datatype strings. Each string has a length
  // equal to num_storage_levels, and contains the characters 0 (bypass), 1 (keep),
  // or X (evaluate both).
  for (unsigned pvi = 0; pvi < unsigned(problem::GetShape()->NumDataSpaces); pvi++)
  {
    auto pv = problem::Shape::DataSpaceID(pvi);

    // Start parsing the user mask string.
    assert(user_bypass_strings.at(pv).length() <= arch_props_.StorageLevels());

    // The first loop runs the length of the user-specified string.
    unsigned level = 0;
    for (; level < user_bypass_strings.at(pv).length(); level++)
    {
      char spec = user_bypass_strings.at(pv).at(level);
      switch (spec)
      {
        case '0':
          mapping.datatype_bypass_nest.at(pvi).reset(level);
          break;

        case '1':
          mapping.datatype_bypass_nest.at(pvi).set(level);
          break;

        case 'X':
          // We allow this to be left un-specified by the user. Default is "keep".
          mapping.datatype_bypass_nest.at(pvi).set(level);
          break;

        default:
          assert(false);
          break;
      }
    }
  } // for (pvi)

    // Finalize mapping.
  mapping.id = 0;

  return mapping;
}

//
// FindTargetTilingLevel()
//
unsigned FindTargetTilingLevel(config::CompoundConfigNode directive, std::string type)
{
  auto num_storage_levels = arch_props_.StorageLevels();

  //
  // Find the target storage level. This can be specified as either a name or an ID.
  //
  std::string storage_level_name;
  unsigned storage_level_id;

  if (directive.lookupValue("target", storage_level_name))
  {
    // Find this name within the storage hierarchy in the arch specs.
    for (storage_level_id = 0; storage_level_id < num_storage_levels; storage_level_id++)
    {
      if (arch_props_.Specs().topology.GetStorageLevel(storage_level_id)->level_name == storage_level_name)
        break;
    }
    if (storage_level_id == num_storage_levels)
    {
      std::cerr << "ERROR: target storage level not found: " << storage_level_name << std::endl;
      exit(1);
    }
  }
  else
  {
    int id;
    assert(directive.lookupValue("target", id));
    assert(id >= 0  && id < int(num_storage_levels));
    storage_level_id = static_cast<unsigned>(id);
  }

  assert(storage_level_id < num_storage_levels);

  //
  // Translate this storage ID to a tiling ID.
  //
  unsigned tiling_level_id;
  if (type == "temporal" || type == "datatype" || type == "bypass")
  {
    // This should always succeed.
    tiling_level_id = arch_props_.TemporalToTiling(storage_level_id);
  }
  else if (type == "spatial")
  {
    // This will fail if this level isn't a spatial tiling level.
    tiling_level_id = arch_props_.SpatialToTiling(storage_level_id);
  }
  else
  {
    std::cerr << "ERROR: unrecognized mapping directive type: " << type << std::endl;
    exit(1);
  }

  return tiling_level_id;
}

//
// Parse user factors.
//
std::map<problem::Shape::DimensionID, int> ParseUserFactors(config::CompoundConfigNode directive)
{
  std::map<problem::Shape::DimensionID, int> retval;

  std::string buffer;
  if (directive.lookupValue("factors", buffer))
  {
    std::regex re("([A-Za-z]+)[[:space:]]*[=]*[[:space:]]*([0-9]+)", std::regex::extended);
    std::smatch sm;
    std::string str = std::string(buffer);

    while (std::regex_search(str, sm, re))
    {
      std::string dimension_name = sm[1];
      problem::Shape::DimensionID dimension;
      try
      {
        dimension = problem::GetShape()->DimensionNameToID.at(dimension_name);
      }
      catch (const std::out_of_range& oor)
      {
        std::cerr << "ERROR: parsing factors: " << buffer << ": dimension " << dimension_name
                  << " not found in problem shape." << std::endl;
        exit(1);
      }

      int end = std::stoi(sm[2]);
      if (end == 0)
      {
        std::cerr << "WARNING: Interpreting 0 to mean full problem dimension instead of residue." << std::endl;
        end = workload_.GetBound(dimension);
      }
      else if (end > workload_.GetBound(dimension))
      {
        std::cerr << "WARNING: Directive " << dimension << "=" << end
                  << " exceeds problem dimension " << dimension << "="
                  << workload_.GetBound(dimension) << ". Setting directive "
                  << dimension << "=" << workload_.GetBound(dimension) << std::endl;
        end = workload_.GetBound(dimension);
      }
      else
      {
        assert(end > 0);
      }

      // Found all the information we need to setup a factor!
      retval[dimension] = end;

      str = sm.suffix().str();
    }
  }

  return retval;
}

//
// Parse user permutations.
//
std::vector<problem::Shape::DimensionID> ParseUserPermutations(config::CompoundConfigNode directive)
{
  std::vector<problem::Shape::DimensionID> retval;

  std::string buffer;
  if (directive.lookupValue("permutation", buffer))
  {
    std::istringstream iss(buffer);
    char token;
    while (iss >> token)
    {
      auto dimension = problem::GetShape()->DimensionNameToID.at(std::string(1, token)); // note: can fault.
      retval.push_back(dimension);
    }
  }

  return retval;
}

//
// Parse user datatype bypass settings.
//
void ParseUserDatatypeBypassSettings(config::CompoundConfigNode directive,
                                     unsigned level,
                                     problem::PerDataSpace<std::string>& user_bypass_strings)
{
  // Datatypes to "keep" at this level.
  if (directive.exists("keep"))
  {
    std::vector<std::string> datatype_strings;
    directive.lookupArrayValue("keep", datatype_strings);
    for (const std::string& datatype_string: datatype_strings)
    {
      auto datatype = problem::GetShape()->DataSpaceNameToID.at(datatype_string);
      user_bypass_strings.at(datatype).at(level) = '1';
    }
  }

  // Datatypes to "bypass" at this level.
  if (directive.exists("bypass"))
  {
    std::vector<std::string> datatype_strings;
    directive.lookupArrayValue("bypass", datatype_strings);
    for (const std::string& datatype_string: datatype_strings)
    {
      auto datatype = problem::GetShape()->DataSpaceNameToID.at(datatype_string);
      user_bypass_strings.at(datatype).at(level) = '0';
    }
  }
}

} // namespace mapping
<commit_msg>Improve error message language.<commit_after>/* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of NVIDIA CORPORATION nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <regex>

#include "parser.hpp"
#include "arch-properties.hpp"

namespace mapping
{

//
// Shared state.
//

ArchProperties arch_props_;
problem::Workload workload_;

//
// Forward declarations.
//
unsigned FindTargetTilingLevel(config::CompoundConfigNode constraint, std::string type);
std::map<problem::Shape::DimensionID, int> ParseUserFactors(config::CompoundConfigNode constraint);
std::vector<problem::Shape::DimensionID> ParseUserPermutations(config::CompoundConfigNode constraint);
void ParseUserDatatypeBypassSettings(config::CompoundConfigNode constraint,
                                     unsigned level,
                                     problem::PerDataSpace<std::string>& user_bypass_strings);
//
// Parse mapping in libconfig format and generate data structure.
//
Mapping ParseAndConstruct(config::CompoundConfigNode config,
                          model::Engine::Specs& arch_specs,
                          problem::Workload workload)
{
  arch_props_.Construct(arch_specs);
  workload_ = workload;

  std::map<unsigned, std::map<problem::Shape::DimensionID, int>> user_factors;
  std::map<unsigned, std::vector<problem::Shape::DimensionID>> user_permutations;
  std::map<unsigned, std::uint32_t> user_spatial_splits;
  problem::PerDataSpace<std::string> user_bypass_strings;

  // Initialize user bypass strings to "XXXXX...1" (note the 1 at the end).
  // FIXME: there's probably a cleaner way/place to initialize this.
  for (unsigned pvi = 0; pvi < unsigned(problem::GetShape()->NumDataSpaces); pvi++)
  {
    std::string xxx(arch_props_.StorageLevels(), 'X');
    xxx.back() = '1';
    user_bypass_strings[problem::Shape::DataSpaceID(pvi)] = xxx;
  }

  // Parse user-provided mapping.
  assert(config.isList());

  // Iterate over all the directives.
  int len = config.getLength();
  for (int i = 0; i < len; i ++)
  {
    auto directive = config[i];
    // Find out if this is a temporal directive or a spatial directive.
    std::string type;
    assert(directive.lookupValue("type", type));

    auto level_id = FindTargetTilingLevel(directive, type);

    if (type == "temporal" || type == "spatial")
    {
      auto level_factors = ParseUserFactors(directive);
      if (level_factors.size() > 0)
      {
        user_factors[level_id] = level_factors;
      }

      auto level_permutations = ParseUserPermutations(directive);
      if (level_permutations.size() > 0)
      {
        user_permutations[level_id] = level_permutations;
      }

      if (type == "spatial")
      {
        // Initialize user spatial splits to map all dimensions to the hardware X-axis.
        std::uint32_t user_split = unsigned(problem::GetShape()->NumDimensions);
        directive.lookupValue("split", user_split);
        user_spatial_splits[level_id] = user_split;
      }
    }
    else if (type == "datatype" || type == "bypass")
    {
      ParseUserDatatypeBypassSettings(directive,
                                      arch_props_.TilingToStorage(level_id),
                                      user_bypass_strings);
    }
    else
    {
      assert(false);
    }
  }

  // Validity checks.
  std::map<problem::Shape::DimensionID, int> dimension_factor_products;
  for (unsigned dim = 0; dim < problem::GetShape()->NumDimensions; dim++)
    dimension_factor_products[dim] = 1;

  // Construct the mapping from the parsed sub-structures.
  // A set of subnests, one for each tiling level.
  loop::NestConfig subnests(arch_props_.TilingLevels());

  // Construct num_storage_levels loop-nest partitions and assign factors, dimensions
  // and spatial split points.
  for (uint64_t level = 0; level < arch_props_.TilingLevels(); level++)
  {
    auto permutation = user_permutations.find(level);
    if (permutation == user_permutations.end())
    {
      std::cerr << "ERROR: parsing mapping: permutation not found for level: "
                << arch_props_.TilingLevelName(level) << std::endl;
      exit(1);
    }
    assert(permutation->second.size() == std::size_t(problem::GetShape()->NumDimensions));

    auto factors = user_factors.find(level);
    if (factors == user_factors.end())
    {
      std::cerr << "ERROR: parsing mapping: factors not found for level: "
                << arch_props_.TilingLevelName(level) << std::endl;
      exit(1);
    }
    assert(factors->second.size() == std::size_t(problem::GetShape()->NumDimensions));

    // Each partition has problem::GetShape()->NumDimensions loops.
    for (unsigned idim = 0; idim < unsigned(problem::GetShape()->NumDimensions); idim++)
    {
      loop::Descriptor loop;
      loop.dimension = permutation->second.at(idim);
      loop.start = 0;
      loop.end = factors->second.at(loop.dimension);
      loop.stride = 1; // FIXME.
      loop.spacetime_dimension = arch_props_.IsSpatial(level)
        ? (idim < user_spatial_splits.at(level) ? spacetime::Dimension::SpaceX : spacetime::Dimension::SpaceY)
        : spacetime::Dimension::Time;
      subnests.at(level).push_back(loop);

      dimension_factor_products[loop.dimension] *= loop.end;
    }
  }

  // All user-provided factors must multiply-up to the dimension size.
  bool fault = false;
  for (unsigned dim = 0; dim < problem::GetShape()->NumDimensions; dim++)
  {
    if (dimension_factor_products[dim] != workload_.GetBound(dim))
    {
      std::cerr << "ERROR: parsing mapping: product of all factors of dimension "
                << problem::GetShape()->DimensionIDToName.at(dim) << " is "
                << dimension_factor_products[dim] << ", which is not equal to "
                << "the dimension size of the workload " << workload_.GetBound(dim)
                << "." << std::endl;
      fault = true;
    }
  }
  if (fault)
  {
    exit(1);
  }

  // Concatenate the subnests to form the final mapping nest.
  Mapping mapping;

  std::uint64_t storage_level = 0;
  for (uint64_t i = 0; i < arch_props_.TilingLevels(); i++)
  {
    uint64_t num_subnests_added = 0;
    for (int dim = 0; dim < int(problem::GetShape()->NumDimensions); dim++)
    {
      // Ignore trivial factors
      // This reduces computation time by 1.5x on average.
      if (subnests[i][dim].start + subnests[i][dim].stride < subnests[i][dim].end)
      {
        mapping.loop_nest.AddLoop(subnests[i][dim]);
        num_subnests_added++;
      }
    }
    if (!arch_props_.IsSpatial(i))
    {
      if (num_subnests_added == 0)
      {
        // Add a trivial temporal nest to make sure
        // we have at least one subnest in each level.
        mapping.loop_nest.AddLoop(problem::Shape::DimensionID(int(problem::GetShape()->NumDimensions) - 1),
                                   0, 1, 1, spacetime::Dimension::Time);
      }
      mapping.loop_nest.AddStorageTilingBoundary();
      storage_level++;
    }
  }

  // The user_mask input is a set of per-datatype strings. Each string has a length
  // equal to num_storage_levels, and contains the characters 0 (bypass), 1 (keep),
  // or X (evaluate both).
  for (unsigned pvi = 0; pvi < unsigned(problem::GetShape()->NumDataSpaces); pvi++)
  {
    auto pv = problem::Shape::DataSpaceID(pvi);

    // Start parsing the user mask string.
    assert(user_bypass_strings.at(pv).length() <= arch_props_.StorageLevels());

    // The first loop runs the length of the user-specified string.
    unsigned level = 0;
    for (; level < user_bypass_strings.at(pv).length(); level++)
    {
      char spec = user_bypass_strings.at(pv).at(level);
      switch (spec)
      {
        case '0':
          mapping.datatype_bypass_nest.at(pvi).reset(level);
          break;

        case '1':
          mapping.datatype_bypass_nest.at(pvi).set(level);
          break;

        case 'X':
          // We allow this to be left un-specified by the user. Default is "keep".
          mapping.datatype_bypass_nest.at(pvi).set(level);
          break;

        default:
          assert(false);
          break;
      }
    }
  } // for (pvi)

    // Finalize mapping.
  mapping.id = 0;

  return mapping;
}

//
// FindTargetTilingLevel()
//
unsigned FindTargetTilingLevel(config::CompoundConfigNode directive, std::string type)
{
  auto num_storage_levels = arch_props_.StorageLevels();

  //
  // Find the target storage level. This can be specified as either a name or an ID.
  //
  std::string storage_level_name;
  unsigned storage_level_id;

  if (directive.lookupValue("target", storage_level_name))
  {
    // Find this name within the storage hierarchy in the arch specs.
    for (storage_level_id = 0; storage_level_id < num_storage_levels; storage_level_id++)
    {
      if (arch_props_.Specs().topology.GetStorageLevel(storage_level_id)->level_name == storage_level_name)
        break;
    }
    if (storage_level_id == num_storage_levels)
    {
      std::cerr << "ERROR: target storage level not found: " << storage_level_name << std::endl;
      exit(1);
    }
  }
  else
  {
    int id;
    assert(directive.lookupValue("target", id));
    assert(id >= 0  && id < int(num_storage_levels));
    storage_level_id = static_cast<unsigned>(id);
  }

  assert(storage_level_id < num_storage_levels);

  //
  // Translate this storage ID to a tiling ID.
  //
  unsigned tiling_level_id;
  if (type == "temporal" || type == "datatype" || type == "bypass")
  {
    // This should always succeed.
    tiling_level_id = arch_props_.TemporalToTiling(storage_level_id);
  }
  else if (type == "spatial")
  {
    // This will fail if this level isn't a spatial tiling level.
    tiling_level_id = arch_props_.SpatialToTiling(storage_level_id);
  }
  else
  {
    std::cerr << "ERROR: unrecognized mapping directive type: " << type << std::endl;
    exit(1);
  }

  return tiling_level_id;
}

//
// Parse user factors.
//
std::map<problem::Shape::DimensionID, int> ParseUserFactors(config::CompoundConfigNode directive)
{
  std::map<problem::Shape::DimensionID, int> retval;

  std::string buffer;
  if (directive.lookupValue("factors", buffer))
  {
    std::regex re("([A-Za-z]+)[[:space:]]*[=]*[[:space:]]*([0-9]+)", std::regex::extended);
    std::smatch sm;
    std::string str = std::string(buffer);

    while (std::regex_search(str, sm, re))
    {
      std::string dimension_name = sm[1];
      problem::Shape::DimensionID dimension;
      try
      {
        dimension = problem::GetShape()->DimensionNameToID.at(dimension_name);
      }
      catch (const std::out_of_range& oor)
      {
        std::cerr << "ERROR: parsing factors: " << buffer << ": dimension " << dimension_name
                  << " not found in problem shape." << std::endl;
        exit(1);
      }

      int end = std::stoi(sm[2]);
      if (end == 0)
      {
        std::cerr << "WARNING: Interpreting 0 to mean full problem dimension instead of residue." << std::endl;
        end = workload_.GetBound(dimension);
      }
      else if (end > workload_.GetBound(dimension))
      {
        std::cerr << "WARNING: Directive " << dimension << "=" << end
                  << " exceeds problem dimension " << dimension << "="
                  << workload_.GetBound(dimension) << ". Setting directive "
                  << dimension << "=" << workload_.GetBound(dimension) << std::endl;
        end = workload_.GetBound(dimension);
      }
      else
      {
        assert(end > 0);
      }

      // Found all the information we need to setup a factor!
      retval[dimension] = end;

      str = sm.suffix().str();
    }
  }

  return retval;
}

//
// Parse user permutations.
//
std::vector<problem::Shape::DimensionID> ParseUserPermutations(config::CompoundConfigNode directive)
{
  std::vector<problem::Shape::DimensionID> retval;

  std::string buffer;
  if (directive.lookupValue("permutation", buffer))
  {
    std::istringstream iss(buffer);
    char token;
    while (iss >> token)
    {
      auto dimension = problem::GetShape()->DimensionNameToID.at(std::string(1, token)); // note: can fault.
      retval.push_back(dimension);
    }
  }

  return retval;
}

//
// Parse user datatype bypass settings.
//
void ParseUserDatatypeBypassSettings(config::CompoundConfigNode directive,
                                     unsigned level,
                                     problem::PerDataSpace<std::string>& user_bypass_strings)
{
  // Datatypes to "keep" at this level.
  if (directive.exists("keep"))
  {
    std::vector<std::string> datatype_strings;
    directive.lookupArrayValue("keep", datatype_strings);
    for (const std::string& datatype_string: datatype_strings)
    {
      auto datatype = problem::GetShape()->DataSpaceNameToID.at(datatype_string);
      user_bypass_strings.at(datatype).at(level) = '1';
    }
  }

  // Datatypes to "bypass" at this level.
  if (directive.exists("bypass"))
  {
    std::vector<std::string> datatype_strings;
    directive.lookupArrayValue("bypass", datatype_strings);
    for (const std::string& datatype_string: datatype_strings)
    {
      auto datatype = problem::GetShape()->DataSpaceNameToID.at(datatype_string);
      user_bypass_strings.at(datatype).at(level) = '0';
    }
  }
}

} // namespace mapping
<|endoftext|>


<commit_before>#include <offboard_control/mavros_adapter.h>

#include <mavros_msgs/CommandBool.h>
#include <mavros_msgs/CommandTOL.h>
#include <mavros_msgs/SetMode.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/TwistStamped.h>

static const std::string PX4_MODE_OFFBOARD = "OFFBOARD";
static const float REQUEST_INTERVAL = 2.0;

MavrosAdapter::MavrosAdapter(ros::NodeHandle &rosNode) {
  this->mRosNode = &rosNode;
  this->mArmingService = this->mRosNode->serviceClient<mavros_msgs::CommandBool>("mavros/cmd/arming");
  this->mSetModeService = this->mRosNode->serviceClient<mavros_msgs::SetMode>("mavros/set_mode");
  this->mStateSubscriber = this->mRosNode->subscribe<mavros_msgs::State>("mavros/state", 1, &MavrosAdapter::stateCallback, this);
  this->mRcInSubscriber = this->mRosNode->subscribe<mavros_msgs::RCIn>("mavros/rc/in", 1, &MavrosAdapter::rcInCallback, this);
  this->mWaypointPublisher = this->mRosNode->advertise<geometry_msgs::PoseStamped>("mavros/setpoint_position/local", 1);
  this->mVelocityPublisher = this->mRosNode->advertise<geometry_msgs::TwistStamped>("mavros/setpoint_velocity/cmd_vel", 1);
  this->mLastRequest = ros::Time::now();
  this->mOffboardMode = OffboardMode::WAYPOINT;
  this->mRcFlightModePulseValue = 0;
  this->mIsRcInterrupt = false;
  this->mIsRunning = false;
  this->mIsEnabled = false;
  this->mMavrosThread = new std::thread(&MavrosAdapter::threadLoop, this);
}

MavrosAdapter::~MavrosAdapter() {
  if (this->mMavrosThread != NULL) {
    this->mIsRunning = false;
    this->mMavrosThread->join();
    delete this->mMavrosThread;
  }
}

void MavrosAdapter::initialize() {
  this->connectToFlightController();
  this->mIsEnabled = true;
}

bool MavrosAdapter::arm(bool doArm) {
  mavros_msgs::CommandBool armMsg;
  armMsg.request.value = doArm;
  return this->mArmingService.call(armMsg);
}

void MavrosAdapter::waypoint(geometry_msgs::Pose pose) {
  this->mOffboardWaypoint = pose;
  this->mOffboardMode = OffboardMode::WAYPOINT;
}

void MavrosAdapter::velocity(geometry_msgs::Twist twist) {
  this->mOffboardVelocity = twist;
  this->mOffboardMode = OffboardMode::VELOCITY;
}

void MavrosAdapter::setEnabled(bool isEnabled) {
  this->mIsEnabled = isEnabled;
}

bool MavrosAdapter::isFcuConnected() const {
  return this->mFcuState.connected;
}

bool MavrosAdapter::isFcuArmed() const {
  return this->mFcuState.armed;
}

bool MavrosAdapter::isEnabled() const {
  return this->mIsEnabled;
}

void MavrosAdapter::stateCallback(const mavros_msgs::State::ConstPtr& msg) {
  this->mFcuState = *msg;
}

void MavrosAdapter::rcInCallback(const mavros_msgs::RCIn::ConstPtr& msg) {
  if (msg->channels.size() >= 5) {
    if (this->mRcFlightModePulseValue != 0 && abs(this->mRcFlightModePulseValue - msg->channels[4]) > 5) {
      if (this->mIsEnabled) {
        ROS_INFO("RC interrupt detected; disabling offboard control.");
        this->mIsEnabled = false;
      }
    }
    this->mRcFlightModePulseValue = msg->channels[4];
  }
}

void MavrosAdapter::publishWaypoint() const {
  geometry_msgs::PoseStamped poseMsg;
  poseMsg.pose = this->mOffboardWaypoint;
  this->mWaypointPublisher.publish(poseMsg);
}

void MavrosAdapter::publishVelocity() const {
  geometry_msgs::TwistStamped twistMsg;
  twistMsg.twist = this->mOffboardVelocity;
  this->mVelocityPublisher.publish(twistMsg);
}

void MavrosAdapter::connectToFlightController() {
  // Before publishing anything, we wait for the connection to be established between mavros and the autopilot.
  // This loop should exit as soon as a heartbeat message is received.
  ROS_INFO("Connecting to flight control unit.");
  ros::Rate rosRate(10.0);
  while (ros::ok() && !this->mFcuState.connected) {
    ros::spinOnce();
    rosRate.sleep();
  }
  ROS_INFO("Connection between MAVROS and flight control unit established.");
}

void MavrosAdapter::configureOffboardMode() {
  if (this->mFcuState.mode != PX4_MODE_OFFBOARD && (ros::Time::now() - this->mLastRequest > ros::Duration(REQUEST_INTERVAL))) {
    // Before entering offboard mode, you must have already started streaming setpoints otherwise the mode switch will be rejected.
    ros::Rate rosRate(20.0);
    for (int i = 40; ros::ok() && i > 0; --i) {
      this->publishWaypoint();
      ros::spinOnce();
      rosRate.sleep();
    }
    mavros_msgs::SetMode setModeCommand;
    setModeCommand.request.custom_mode = PX4_MODE_OFFBOARD;
    if (this->mSetModeService.call(setModeCommand)) {
      ROS_INFO_STREAM("Setting flight mode to " + PX4_MODE_OFFBOARD + ".");
    }
    this->mLastRequest = ros::Time::now();
  }
}

void MavrosAdapter::threadLoop() {
  ros::Rate rosRate(20.0);
  this->mIsRunning = true;
  while (this->mRosNode->ok() && this->mIsRunning) {
    if (this->mIsEnabled) {
      this->configureOffboardMode();
      switch (this->mOffboardMode) {
      case OffboardMode::WAYPOINT:
        this->publishWaypoint();
        break;
      case OffboardMode::VELOCITY:
        this->publishVelocity();
        break;
      default:
        break;
      }
    }
    ros::spinOnce();
    rosRate.sleep();
  }
}
<commit_msg>Fixed casting issue when detecting change to flight mode.<commit_after>#include <offboard_control/mavros_adapter.h>

#include <mavros_msgs/CommandBool.h>
#include <mavros_msgs/CommandTOL.h>
#include <mavros_msgs/SetMode.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/TwistStamped.h>

static const std::string PX4_MODE_OFFBOARD = "OFFBOARD";
static const float REQUEST_INTERVAL = 2.0;

MavrosAdapter::MavrosAdapter(ros::NodeHandle &rosNode) {
  this->mRosNode = &rosNode;
  this->mArmingService = this->mRosNode->serviceClient<mavros_msgs::CommandBool>("mavros/cmd/arming");
  this->mSetModeService = this->mRosNode->serviceClient<mavros_msgs::SetMode>("mavros/set_mode");
  this->mStateSubscriber = this->mRosNode->subscribe<mavros_msgs::State>("mavros/state", 1, &MavrosAdapter::stateCallback, this);
  this->mRcInSubscriber = this->mRosNode->subscribe<mavros_msgs::RCIn>("mavros/rc/in", 1, &MavrosAdapter::rcInCallback, this);
  this->mWaypointPublisher = this->mRosNode->advertise<geometry_msgs::PoseStamped>("mavros/setpoint_position/local", 1);
  this->mVelocityPublisher = this->mRosNode->advertise<geometry_msgs::TwistStamped>("mavros/setpoint_velocity/cmd_vel", 1);
  this->mLastRequest = ros::Time::now();
  this->mOffboardMode = OffboardMode::WAYPOINT;
  this->mRcFlightModePulseValue = 0;
  this->mIsRcInterrupt = false;
  this->mIsRunning = false;
  this->mIsEnabled = false;
  this->mMavrosThread = new std::thread(&MavrosAdapter::threadLoop, this);
}

MavrosAdapter::~MavrosAdapter() {
  if (this->mMavrosThread != NULL) {
    this->mIsRunning = false;
    this->mMavrosThread->join();
    delete this->mMavrosThread;
  }
}

void MavrosAdapter::initialize() {
  this->connectToFlightController();
  this->mIsEnabled = true;
}

bool MavrosAdapter::arm(bool doArm) {
  mavros_msgs::CommandBool armMsg;
  armMsg.request.value = doArm;
  return this->mArmingService.call(armMsg);
}

void MavrosAdapter::waypoint(geometry_msgs::Pose pose) {
  this->mOffboardWaypoint = pose;
  this->mOffboardMode = OffboardMode::WAYPOINT;
}

void MavrosAdapter::velocity(geometry_msgs::Twist twist) {
  this->mOffboardVelocity = twist;
  this->mOffboardMode = OffboardMode::VELOCITY;
}

void MavrosAdapter::setEnabled(bool isEnabled) {
  this->mIsEnabled = isEnabled;
}

bool MavrosAdapter::isFcuConnected() const {
  return this->mFcuState.connected;
}

bool MavrosAdapter::isFcuArmed() const {
  return this->mFcuState.armed;
}

bool MavrosAdapter::isEnabled() const {
  return this->mIsEnabled;
}

void MavrosAdapter::stateCallback(const mavros_msgs::State::ConstPtr& msg) {
  this->mFcuState = *msg;
}

void MavrosAdapter::rcInCallback(const mavros_msgs::RCIn::ConstPtr& msg) {
  if (msg->channels.size() >= 5) {
    if (this->mRcFlightModePulseValue != 0 && abs((int)this->mRcFlightModePulseValue - (int)msg->channels[4]) > 5) {
      if (this->mIsEnabled) {
        ROS_INFO("RC interrupt detected; disabling offboard control.");
        this->mIsEnabled = false;
      }
    }
    this->mRcFlightModePulseValue = msg->channels[4];
  }
}

void MavrosAdapter::publishWaypoint() const {
  geometry_msgs::PoseStamped poseMsg;
  poseMsg.pose = this->mOffboardWaypoint;
  this->mWaypointPublisher.publish(poseMsg);
}

void MavrosAdapter::publishVelocity() const {
  geometry_msgs::TwistStamped twistMsg;
  twistMsg.twist = this->mOffboardVelocity;
  this->mVelocityPublisher.publish(twistMsg);
}

void MavrosAdapter::connectToFlightController() {
  // Before publishing anything, we wait for the connection to be established between mavros and the autopilot.
  // This loop should exit as soon as a heartbeat message is received.
  ROS_INFO("Connecting to flight control unit.");
  ros::Rate rosRate(10.0);
  while (ros::ok() && !this->mFcuState.connected) {
    ros::spinOnce();
    rosRate.sleep();
  }
  ROS_INFO("Connection between MAVROS and flight control unit established.");
}

void MavrosAdapter::configureOffboardMode() {
  if (this->mFcuState.mode != PX4_MODE_OFFBOARD && (ros::Time::now() - this->mLastRequest > ros::Duration(REQUEST_INTERVAL))) {
    // Before entering offboard mode, you must have already started streaming setpoints otherwise the mode switch will be rejected.
    ros::Rate rosRate(20.0);
    for (int i = 40; ros::ok() && i > 0; --i) {
      this->publishWaypoint();
      ros::spinOnce();
      rosRate.sleep();
    }
    mavros_msgs::SetMode setModeCommand;
    setModeCommand.request.custom_mode = PX4_MODE_OFFBOARD;
    if (this->mSetModeService.call(setModeCommand)) {
      ROS_INFO_STREAM("Setting flight mode to " + PX4_MODE_OFFBOARD + ".");
    }
    this->mLastRequest = ros::Time::now();
  }
}

void MavrosAdapter::threadLoop() {
  ros::Rate rosRate(20.0);
  this->mIsRunning = true;
  while (this->mRosNode->ok() && this->mIsRunning) {
    if (this->mIsEnabled) {
      this->configureOffboardMode();
      switch (this->mOffboardMode) {
      case OffboardMode::WAYPOINT:
        this->publishWaypoint();
        break;
      case OffboardMode::VELOCITY:
        this->publishVelocity();
        break;
      default:
        break;
      }
    }
    ros::spinOnce();
    rosRate.sleep();
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2013, 2015-2016, 2018 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Erik Hallnor
 *          Andreas Sandberg
 *          Andreas Hansson
 */

/** @file
 * Declaration of a high-level queue structure
 */

#ifndef __MEM_CACHE_QUEUE_HH__
#define __MEM_CACHE_QUEUE_HH__

#include <cassert>
#include <string>

#include "base/logging.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "debug/Drain.hh"
#include "mem/cache/queue_entry.hh"
#include "mem/packet.hh"
#include "sim/core.hh"
#include "sim/drain.hh"

/**
 * A high-level queue interface, to be used by both the MSHR queue and
 * the write buffer.
 */
template<class Entry>
class Queue : public Drainable
{
  protected:
    /** Local label (for functional print requests) */
    const std::string label;

    /**
     * The total number of entries in this queue. This number is set
     * as the number of entries requested plus any reserve. This
     * allows for the same number of effective entries while still
     * maintaining an overflow reserve.
     */
    const int numEntries;

    /**
     * The number of entries to hold as a temporary overflow
     * space. This is used to allow temporary overflow of the number
     * of entries as we only check the full condition under certain
     * conditions.
     */
    const int numReserve;

    /**  Actual storage. */
    std::vector<Entry> entries;
    /** Holds pointers to all allocated entries. */
    typename Entry::List allocatedList;
    /** Holds pointers to entries that haven't been sent downstream. */
    typename Entry::List readyList;
    /** Holds non allocated entries. */
    typename Entry::List freeList;

    typename Entry::Iterator addToReadyList(Entry* entry)
    {
        if (readyList.empty() ||
            readyList.back()->readyTime <= entry->readyTime) {
            return readyList.insert(readyList.end(), entry);
        }

        for (auto i = readyList.begin(); i != readyList.end(); ++i) {
            if ((*i)->readyTime > entry->readyTime) {
                return readyList.insert(i, entry);
            }
        }
        panic("Failed to add to ready list.");
    }

    /** The number of entries that are in service. */
    int _numInService;

    /** The number of currently allocated entries. */
    int allocated;

  public:

    /**
     * Create a queue with a given number of entries.
     *
     * @param num_entries The number of entries in this queue.
     * @param reserve The extra overflow entries needed.
     */
    Queue(const std::string &_label, int num_entries, int reserve) :
        label(_label), numEntries(num_entries + reserve),
        numReserve(reserve), entries(numEntries), _numInService(0),
        allocated(0)
    {
        for (int i = 0; i < numEntries; ++i) {
            freeList.push_back(&entries[i]);
        }
    }

    bool isEmpty() const
    {
        return allocated == 0;
    }

    bool isFull() const
    {
        return (allocated >= numEntries - numReserve);
    }

    int numInService() const
    {
        return _numInService;
    }

    /**
     * Find the first entry that matches the provided address.
     *
     * @param blk_addr The block address to find.
     * @param is_secure True if the target memory space is secure.
     * @param ignore_uncacheable Should uncacheables be ignored or not
     * @return Pointer to the matching WriteQueueEntry, null if not found.
     */
    Entry* findMatch(Addr blk_addr, bool is_secure,
                     bool ignore_uncacheable = true) const
    {
        for (const auto& entry : allocatedList) {
            // we ignore any entries allocated for uncacheable
            // accesses and simply ignore them when matching, in the
            // cache we never check for matches when adding new
            // uncacheable entries, and we do not want normal
            // cacheable accesses being added to an WriteQueueEntry
            // serving an uncacheable access
            if (!(ignore_uncacheable && entry->isUncacheable()) &&
                entry->blkAddr == blk_addr && entry->isSecure == is_secure) {
                return entry;
            }
        }
        return nullptr;
    }

    bool trySatisfyFunctional(PacketPtr pkt, Addr blk_addr)
    {
        pkt->pushLabel(label);
        for (const auto& entry : allocatedList) {
            if (entry->blkAddr == blk_addr && entry->trySatisfyFunctional(pkt)) {
                pkt->popLabel();
                return true;
            }
        }
        pkt->popLabel();
        return false;
    }

    /**
     * Find any pending requests that overlap the given request.
     * @param blk_addr Block address.
     * @param is_secure True if the target memory space is secure.
     * @return A pointer to the earliest matching WriteQueueEntry.
     */
    Entry* findPending(Addr blk_addr, bool is_secure) const
    {
        for (const auto& entry : readyList) {
            if (entry->blkAddr == blk_addr && entry->isSecure == is_secure) {
                return entry;
            }
        }
        return nullptr;
    }

    /**
     * Returns the WriteQueueEntry at the head of the readyList.
     * @return The next request to service.
     */
    Entry* getNext() const
    {
        if (readyList.empty() || readyList.front()->readyTime > curTick()) {
            return nullptr;
        }
        return readyList.front();
    }

    Tick nextReadyTime() const
    {
        return readyList.empty() ? MaxTick : readyList.front()->readyTime;
    }

    /**
     * Removes the given entry from the queue. This places the entry
     * on the free list.
     *
     * @param entry
     */
    void deallocate(Entry *entry)
    {
        allocatedList.erase(entry->allocIter);
        freeList.push_front(entry);
        allocated--;
        if (entry->inService) {
            _numInService--;
        } else {
            readyList.erase(entry->readyIter);
        }
        entry->deallocate();
        if (drainState() == DrainState::Draining && allocated == 0) {
            // Notify the drain manager that we have completed
            // draining if there are no other outstanding requests in
            // this queue.
            DPRINTF(Drain, "Queue now empty, signalling drained\n");
            signalDrainDone();
        }
    }

    DrainState drain() override
    {
        return allocated == 0 ? DrainState::Drained : DrainState::Draining;
    }
};

#endif //__MEM_CACHE_QUEUE_HH__
<commit_msg>mem-cache: Assert Entry inherits from QueueEntry in Queue<commit_after>/*
 * Copyright (c) 2012-2013, 2015-2016, 2018 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Erik Hallnor
 *          Andreas Sandberg
 *          Andreas Hansson
 */

/** @file
 * Declaration of a high-level queue structure
 */

#ifndef __MEM_CACHE_QUEUE_HH__
#define __MEM_CACHE_QUEUE_HH__

#include <cassert>
#include <string>
#include <type_traits>

#include "base/logging.hh"
#include "base/trace.hh"
#include "base/types.hh"
#include "debug/Drain.hh"
#include "mem/cache/queue_entry.hh"
#include "mem/packet.hh"
#include "sim/core.hh"
#include "sim/drain.hh"

/**
 * A high-level queue interface, to be used by both the MSHR queue and
 * the write buffer.
 */
template<class Entry>
class Queue : public Drainable
{
    static_assert(std::is_base_of<QueueEntry, Entry>::value,
        "Entry must be derived from QueueEntry");

  protected:
    /** Local label (for functional print requests) */
    const std::string label;

    /**
     * The total number of entries in this queue. This number is set
     * as the number of entries requested plus any reserve. This
     * allows for the same number of effective entries while still
     * maintaining an overflow reserve.
     */
    const int numEntries;

    /**
     * The number of entries to hold as a temporary overflow
     * space. This is used to allow temporary overflow of the number
     * of entries as we only check the full condition under certain
     * conditions.
     */
    const int numReserve;

    /**  Actual storage. */
    std::vector<Entry> entries;
    /** Holds pointers to all allocated entries. */
    typename Entry::List allocatedList;
    /** Holds pointers to entries that haven't been sent downstream. */
    typename Entry::List readyList;
    /** Holds non allocated entries. */
    typename Entry::List freeList;

    typename Entry::Iterator addToReadyList(Entry* entry)
    {
        if (readyList.empty() ||
            readyList.back()->readyTime <= entry->readyTime) {
            return readyList.insert(readyList.end(), entry);
        }

        for (auto i = readyList.begin(); i != readyList.end(); ++i) {
            if ((*i)->readyTime > entry->readyTime) {
                return readyList.insert(i, entry);
            }
        }
        panic("Failed to add to ready list.");
    }

    /** The number of entries that are in service. */
    int _numInService;

    /** The number of currently allocated entries. */
    int allocated;

  public:

    /**
     * Create a queue with a given number of entries.
     *
     * @param num_entries The number of entries in this queue.
     * @param reserve The extra overflow entries needed.
     */
    Queue(const std::string &_label, int num_entries, int reserve) :
        label(_label), numEntries(num_entries + reserve),
        numReserve(reserve), entries(numEntries), _numInService(0),
        allocated(0)
    {
        for (int i = 0; i < numEntries; ++i) {
            freeList.push_back(&entries[i]);
        }
    }

    bool isEmpty() const
    {
        return allocated == 0;
    }

    bool isFull() const
    {
        return (allocated >= numEntries - numReserve);
    }

    int numInService() const
    {
        return _numInService;
    }

    /**
     * Find the first entry that matches the provided address.
     *
     * @param blk_addr The block address to find.
     * @param is_secure True if the target memory space is secure.
     * @param ignore_uncacheable Should uncacheables be ignored or not
     * @return Pointer to the matching WriteQueueEntry, null if not found.
     */
    Entry* findMatch(Addr blk_addr, bool is_secure,
                     bool ignore_uncacheable = true) const
    {
        for (const auto& entry : allocatedList) {
            // we ignore any entries allocated for uncacheable
            // accesses and simply ignore them when matching, in the
            // cache we never check for matches when adding new
            // uncacheable entries, and we do not want normal
            // cacheable accesses being added to an WriteQueueEntry
            // serving an uncacheable access
            if (!(ignore_uncacheable && entry->isUncacheable()) &&
                entry->blkAddr == blk_addr && entry->isSecure == is_secure) {
                return entry;
            }
        }
        return nullptr;
    }

    bool trySatisfyFunctional(PacketPtr pkt, Addr blk_addr)
    {
        pkt->pushLabel(label);
        for (const auto& entry : allocatedList) {
            if (entry->blkAddr == blk_addr && entry->trySatisfyFunctional(pkt)) {
                pkt->popLabel();
                return true;
            }
        }
        pkt->popLabel();
        return false;
    }

    /**
     * Find any pending requests that overlap the given request.
     * @param blk_addr Block address.
     * @param is_secure True if the target memory space is secure.
     * @return A pointer to the earliest matching WriteQueueEntry.
     */
    Entry* findPending(Addr blk_addr, bool is_secure) const
    {
        for (const auto& entry : readyList) {
            if (entry->blkAddr == blk_addr && entry->isSecure == is_secure) {
                return entry;
            }
        }
        return nullptr;
    }

    /**
     * Returns the WriteQueueEntry at the head of the readyList.
     * @return The next request to service.
     */
    Entry* getNext() const
    {
        if (readyList.empty() || readyList.front()->readyTime > curTick()) {
            return nullptr;
        }
        return readyList.front();
    }

    Tick nextReadyTime() const
    {
        return readyList.empty() ? MaxTick : readyList.front()->readyTime;
    }

    /**
     * Removes the given entry from the queue. This places the entry
     * on the free list.
     *
     * @param entry
     */
    void deallocate(Entry *entry)
    {
        allocatedList.erase(entry->allocIter);
        freeList.push_front(entry);
        allocated--;
        if (entry->inService) {
            _numInService--;
        } else {
            readyList.erase(entry->readyIter);
        }
        entry->deallocate();
        if (drainState() == DrainState::Draining && allocated == 0) {
            // Notify the drain manager that we have completed
            // draining if there are no other outstanding requests in
            // this queue.
            DPRINTF(Drain, "Queue now empty, signalling drained\n");
            signalDrainDone();
        }
    }

    DrainState drain() override
    {
        return allocated == 0 ? DrainState::Drained : DrainState::Draining;
    }
};

#endif //__MEM_CACHE_QUEUE_HH__
<|endoftext|>


<commit_before>// @(#)root/tree:$Id$
// Author: Rene Brun   07/04/2001

/*************************************************************************
 * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TFriendElement                                                       //
//                                                                      //
// A TFriendElement TF describes a TTree object TF in a file.           //
// When a TFriendElement TF is added to the the list of friends of an   //
// existing TTree T, any variable from TF can be referenced in a query  //
// to T.                                                                //
//                                                                      //
// To add a TFriendElement to an existing TTree T, do:                  //
//       T.AddFriend("friendTreename","friendTreeFile");                //
//                                                                      //
//  See TTree::AddFriend for more information.                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTree.h"
#include "TFriendElement.h"
#include "TFile.h"
#include "TROOT.h"

R__EXTERN TTree *gTree;

ClassImp(TFriendElement)

//______________________________________________________________________________
TFriendElement::TFriendElement() : TNamed()
{
//*-*-*-*-*-*Default constructor for a friend element*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        =======================================

   fFile       = 0;
   fTree       = 0;
   fOwnFile    = kFALSE;
   fParentTree = gTree;
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, const char *treename, const char *filename)
    :TNamed(treename,filename)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a friend element*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ======================
//
// If treename is of the form "a=b", an alias called "a" is created for
// treename = "b" by default the alias name is the name of the tree.

   fFile       = 0;
   fTree       = 0;
   fOwnFile    = kTRUE;
   fParentTree = tree;
   fTreeName   = treename;
   if (strchr(treename,'=')) {
      char *temp = Compress(treename);
      char *equal = strchr(temp,'=');
      *equal=0;
      fTreeName = equal+1;
      SetName(temp);
      delete [] temp;
   }

   Connect();
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, const char *treename, TFile *file)
    :TNamed(treename,file?file->GetName():"")
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a friend element*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ======================
//
// If treename is of the form "a=b", an alias called "a" is created for
// treename = "b" by default the alias name is the name of the tree.
// The passed TFile is managed by the user (i.e. user must delete the TFile).

   fFile       = file;
   fTree       = 0;
   fOwnFile    = kFALSE;
   fParentTree = tree;
   fTreeName   = treename;
   if (strchr(treename,'=')) {
      char *temp = Compress(treename);
      char *equal = strchr(temp,'=');
      *equal=0;
      fTreeName = equal+1;
      SetName(temp);
      delete [] temp;
   }

   Connect();
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, TTree* friendtree, const char *alias)
   : TNamed(friendtree?friendtree->GetName():"",
            friendtree
            ? (   friendtree->GetDirectory()
                  ? (    friendtree->GetDirectory()->GetFile()
                         ? friendtree->GetDirectory()->GetFile()->GetName()
                         :  "")
                  : "")
            :  "")
{
   // Create a friend element.

   fTree       = friendtree;
   fTreeName   = "";
   fFile       = 0;
   if (fTree) {
      fTreeName   = fTree->GetName();
      if (fTree->GetDirectory()) fFile = fTree->GetDirectory()->GetFile();
   }
   fOwnFile    = kFALSE;
   fParentTree = tree;
   if (alias && strlen(alias)) {
      char *temp = Compress(alias);
      SetName(temp);
      delete [] temp;
   }

   // No need to Connect.
}

//______________________________________________________________________________
TFriendElement::TFriendElement(const TFriendElement& tfe) :
   TNamed(tfe),
   fParentTree(tfe.fParentTree),
   fTree(tfe.fTree),
   fFile(tfe.fFile),
   fTreeName(tfe.fTreeName),
   fOwnFile(tfe.fOwnFile)
{
   // Copy constructor
}

//______________________________________________________________________________
TFriendElement& TFriendElement::operator=(const TFriendElement& tfe)
{
   // Equal operator
   if(this!=&tfe) {
      TNamed::operator=(tfe);
      fParentTree=tfe.fParentTree;
      fTree=tfe.fTree;
      fFile=tfe.fFile;
      fTreeName=tfe.fTreeName;
      fOwnFile=tfe.fOwnFile;
   } return *this;
}

//______________________________________________________________________________
TFriendElement::~TFriendElement()
{
   // Destructor.  Disconnect from the owning tree if needed.

   DisConnect();
}

//_______________________________________________________________________
TTree *TFriendElement::Connect()
{
   // Connect file and return TTree.

   GetFile();
   return GetTree();
}

//_______________________________________________________________________
TTree *TFriendElement::DisConnect()
{
   // DisConnect file and TTree.

   if (fOwnFile) delete fFile;
   fFile = 0;
   fTree = 0;
   return 0;
}

//_______________________________________________________________________
TFile *TFriendElement::GetFile()
{
   // Return pointer to TFile containing this friend TTree.

   if (fFile || IsZombie()) return fFile;

   if (strlen(GetTitle())) {
      TDirectory::TContext ctxt(gDirectory, 0);
      fFile = TFile::Open(GetTitle());
      fOwnFile = kTRUE;
   } else {
      TDirectory *dir = fParentTree->GetDirectory();
      if (dir) {
         fFile = dir->GetFile();
         fOwnFile = kFALSE;
      }
   }
   if (fFile && fFile->IsZombie()) {
      MakeZombie();
      delete fFile;
      fFile = 0;
   }
   return fFile;
}

//_______________________________________________________________________
TTree *TFriendElement::GetTree()
{
   // Return pointer to friend TTree.

   if (fTree) return fTree;

   if (GetFile()) {
      fFile->GetObject(GetTreeName(),fTree);
      if (fTree) return fTree;
   }

   // This could be a memory tree or chain
   fTree = dynamic_cast<TTree*>( gROOT->FindObject(GetTreeName()) );

   return fTree;
}

//_______________________________________________________________________
void TFriendElement::ls(Option_t *) const
{
   // List this friend element.

   printf(" Friend Tree: %s in file: %s\n",GetName(),GetTitle());
}
<commit_msg>If the TreeFriend is entered via a TTree*, properly detect that it is in the same file and do _not_ record the filename (since we will alway know where to find it\!)<commit_after>// @(#)root/tree:$Id$
// Author: Rene Brun   07/04/2001

/*************************************************************************
 * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TFriendElement                                                       //
//                                                                      //
// A TFriendElement TF describes a TTree object TF in a file.           //
// When a TFriendElement TF is added to the the list of friends of an   //
// existing TTree T, any variable from TF can be referenced in a query  //
// to T.                                                                //
//                                                                      //
// To add a TFriendElement to an existing TTree T, do:                  //
//       T.AddFriend("friendTreename","friendTreeFile");                //
//                                                                      //
//  See TTree::AddFriend for more information.                          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTree.h"
#include "TFriendElement.h"
#include "TFile.h"
#include "TROOT.h"

R__EXTERN TTree *gTree;

ClassImp(TFriendElement)

//______________________________________________________________________________
TFriendElement::TFriendElement() : TNamed()
{
//*-*-*-*-*-*Default constructor for a friend element*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*        =======================================

   fFile       = 0;
   fTree       = 0;
   fOwnFile    = kFALSE;
   fParentTree = gTree;
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, const char *treename, const char *filename)
    :TNamed(treename,filename)
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a friend element*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ======================
//
// If treename is of the form "a=b", an alias called "a" is created for
// treename = "b" by default the alias name is the name of the tree.

   fFile       = 0;
   fTree       = 0;
   fOwnFile    = kTRUE;
   fParentTree = tree;
   fTreeName   = treename;
   if (strchr(treename,'=')) {
      char *temp = Compress(treename);
      char *equal = strchr(temp,'=');
      *equal=0;
      fTreeName = equal+1;
      SetName(temp);
      delete [] temp;
   }

   Connect();
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, const char *treename, TFile *file)
    :TNamed(treename,file?file->GetName():"")
{
//*-*-*-*-*-*-*-*-*-*-*-*-*Create a friend element*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-*                      ======================
//
// If treename is of the form "a=b", an alias called "a" is created for
// treename = "b" by default the alias name is the name of the tree.
// The passed TFile is managed by the user (i.e. user must delete the TFile).

   fFile       = file;
   fTree       = 0;
   fOwnFile    = kFALSE;
   fParentTree = tree;
   fTreeName   = treename;
   if (fParentTree && fParentTree->GetDirectory()
       && fTree->GetDirectory()->GetFile() == fFile) {
      // The friend and the TTree are in the same file, let's not record
      // the filename.
      SetTitle("");
   }
   if (strchr(treename,'=')) {
      char *temp = Compress(treename);
      char *equal = strchr(temp,'=');
      *equal=0;
      fTreeName = equal+1;
      SetName(temp);
      delete [] temp;
   }

   Connect();
}

//______________________________________________________________________________
TFriendElement::TFriendElement(TTree *tree, TTree* friendtree, const char *alias)
   : TNamed(friendtree?friendtree->GetName():"",
            friendtree
            ? (   friendtree->GetDirectory()
                  ? (    friendtree->GetDirectory()->GetFile()
                         ? friendtree->GetDirectory()->GetFile()->GetName()
                         :  "")
                  : "")
            :  "")
{
   // Create a friend element.

   fTree       = friendtree;
   fTreeName   = "";
   fFile       = 0;
   fOwnFile    = kFALSE;
   fParentTree = tree;
   if (fTree) {
      fTreeName   = fTree->GetName();
      if (fTree->GetDirectory()) fFile = fTree->GetDirectory()->GetFile();
      if (fParentTree && fParentTree->GetDirectory()
          && fTree->GetDirectory()->GetFile() == fFile) {
         // The friend and the TTree are in the same file, let's not record
         // the filename.
         SetTitle("");
      }
   }
   if (alias && strlen(alias)) {
      char *temp = Compress(alias);
      SetName(temp);
      delete [] temp;
   }

   // No need to Connect.
}

//______________________________________________________________________________
TFriendElement::TFriendElement(const TFriendElement& tfe) :
   TNamed(tfe),
   fParentTree(tfe.fParentTree),
   fTree(tfe.fTree),
   fFile(tfe.fFile),
   fTreeName(tfe.fTreeName),
   fOwnFile(tfe.fOwnFile)
{
   // Copy constructor
}

//______________________________________________________________________________
TFriendElement& TFriendElement::operator=(const TFriendElement& tfe)
{
   // Equal operator
   if(this!=&tfe) {
      TNamed::operator=(tfe);
      fParentTree=tfe.fParentTree;
      fTree=tfe.fTree;
      fFile=tfe.fFile;
      fTreeName=tfe.fTreeName;
      fOwnFile=tfe.fOwnFile;
   } return *this;
}

//______________________________________________________________________________
TFriendElement::~TFriendElement()
{
   // Destructor.  Disconnect from the owning tree if needed.

   DisConnect();
}

//_______________________________________________________________________
TTree *TFriendElement::Connect()
{
   // Connect file and return TTree.

   GetFile();
   return GetTree();
}

//_______________________________________________________________________
TTree *TFriendElement::DisConnect()
{
   // DisConnect file and TTree.

   if (fOwnFile) delete fFile;
   fFile = 0;
   fTree = 0;
   return 0;
}

//_______________________________________________________________________
TFile *TFriendElement::GetFile()
{
   // Return pointer to TFile containing this friend TTree.

   if (fFile || IsZombie()) return fFile;

   if (strlen(GetTitle())) {
      TDirectory::TContext ctxt(gDirectory, 0);
      fFile = TFile::Open(GetTitle());
      fOwnFile = kTRUE;
   } else {
      TDirectory *dir = fParentTree->GetDirectory();
      if (dir) {
         fFile = dir->GetFile();
         fOwnFile = kFALSE;
      }
   }
   if (fFile && fFile->IsZombie()) {
      MakeZombie();
      delete fFile;
      fFile = 0;
   }
   return fFile;
}

//_______________________________________________________________________
TTree *TFriendElement::GetTree()
{
   // Return pointer to friend TTree.

   if (fTree) return fTree;

   if (GetFile()) {
      fFile->GetObject(GetTreeName(),fTree);
      if (fTree) return fTree;
   }

   // This could be a memory tree or chain
   fTree = dynamic_cast<TTree*>( gROOT->FindObject(GetTreeName()) );

   return fTree;
}

//_______________________________________________________________________
void TFriendElement::ls(Option_t *) const
{
   // List this friend element.

   printf(" Friend Tree: %s in file: %s\n",GetName(),GetTitle());
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ftpintreq.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 13:51:29 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_ucb.hxx"
#include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
#include <com/sun/star/ucb/NameClash.hpp>
#include "ftpintreq.hxx"

using namespace cppu;
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::ucb;
using namespace com::sun::star::task;
using namespace ftp;

XInteractionApproveImpl::XInteractionApproveImpl()
    : m_bSelected(false)
{
}

void SAL_CALL
XInteractionApproveImpl::acquire( void )
    throw()
{
    OWeakObject::acquire();
}

void SAL_CALL
XInteractionApproveImpl::release( void )
    throw()
{
    OWeakObject::release();
}

Any SAL_CALL
XInteractionApproveImpl::queryInterface( const Type& rType )
    throw( RuntimeException )
{
    Any aRet = cppu::queryInterface(
        rType,
        SAL_STATIC_CAST( lang::XTypeProvider*, this ),
        SAL_STATIC_CAST( XInteractionApprove*,this) );
    return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
}

//////////////////////////////////////////////////////////////////////////////
//  XTypeProvider
//////////////////////////////////////////////////////////////////////////////

XTYPEPROVIDER_IMPL_2( XInteractionApproveImpl,
                      XTypeProvider,
                      XInteractionApprove )

void SAL_CALL XInteractionApproveImpl::select()
    throw (RuntimeException)
{
    m_bSelected = true;
}

bool XInteractionApproveImpl::isSelected() const
{
    return m_bSelected;
}

// XInteractionDisapproveImpl

XInteractionDisapproveImpl::XInteractionDisapproveImpl()
    : m_bSelected(false)
{
}

void SAL_CALL
XInteractionDisapproveImpl::acquire( void )
    throw()
{
    OWeakObject::acquire();
}

void SAL_CALL
XInteractionDisapproveImpl::release( void )
    throw()
{
    OWeakObject::release();
}

Any SAL_CALL
XInteractionDisapproveImpl::queryInterface( const Type& rType )
    throw( RuntimeException )
{
    Any aRet = cppu::queryInterface(
        rType,
        SAL_STATIC_CAST( lang::XTypeProvider*, this ),
        SAL_STATIC_CAST( XInteractionDisapprove*,this) );
    return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
}

//////////////////////////////////////////////////////////////////////////////
//  XTypeProvider
//////////////////////////////////////////////////////////////////////////////

XTYPEPROVIDER_IMPL_2( XInteractionDisapproveImpl,
                      XTypeProvider,
                      XInteractionDisapprove )

void SAL_CALL XInteractionDisapproveImpl::select()
    throw (RuntimeException)

{
    m_bSelected = true;
}

bool XInteractionDisapproveImpl::isSelected() const
{
    return m_bSelected;
}

// XInteractionRequestImpl

XInteractionRequestImpl::XInteractionRequestImpl(const rtl::OUString& aName)
    : p1( new XInteractionApproveImpl ),
      p2( new XInteractionDisapproveImpl ),
      m_aName(aName),
      m_aSeq( 2 )
{
    m_aSeq[0] = Reference<XInteractionContinuation>(p1);
    m_aSeq[1] = Reference<XInteractionContinuation>(p2);
}

void SAL_CALL
XInteractionRequestImpl::acquire( void )
    throw()
{
    OWeakObject::acquire();
}

void SAL_CALL
XInteractionRequestImpl::release( void )
    throw()
{
    OWeakObject::release();
}

Any SAL_CALL
XInteractionRequestImpl::queryInterface( const Type& rType )
    throw( RuntimeException )
{
    Any aRet = cppu::queryInterface(
        rType,
        SAL_STATIC_CAST( lang::XTypeProvider*, this ),
        SAL_STATIC_CAST( XInteractionRequest*,this) );
    return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
}

//////////////////////////////////////////////////////////////////////////////
//  XTypeProvider
/////////////////////////////////////////////////////////////////////////////

XTYPEPROVIDER_IMPL_2( XInteractionRequestImpl,
                      XTypeProvider,
                      XInteractionRequest )

Any SAL_CALL XInteractionRequestImpl::getRequest(  )
    throw (RuntimeException)
{
    Any aAny;
    UnsupportedNameClashException excep;
    excep.NameClash = NameClash::ERROR;
    aAny <<= excep;
    return aAny;
}

Sequence<Reference<XInteractionContinuation > > SAL_CALL
XInteractionRequestImpl::getContinuations(  )
    throw (RuntimeException)
{
    return m_aSeq;
}

bool XInteractionRequestImpl::aborted() const
{
    return p2->isSelected();
}

bool XInteractionRequestImpl::approved() const
{
    return p1->isSelected();
}

<commit_msg>INTEGRATION: CWS changefileheader (1.4.118); FILE MERGED 2008/03/31 15:30:20 rt 1.4.118.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: ftpintreq.cxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_ucb.hxx"
#include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
#include <com/sun/star/ucb/NameClash.hpp>
#include "ftpintreq.hxx"

using namespace cppu;
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::ucb;
using namespace com::sun::star::task;
using namespace ftp;

XInteractionApproveImpl::XInteractionApproveImpl()
    : m_bSelected(false)
{
}

void SAL_CALL
XInteractionApproveImpl::acquire( void )
    throw()
{
    OWeakObject::acquire();
}

void SAL_CALL
XInteractionApproveImpl::release( void )
    throw()
{
    OWeakObject::release();
}

Any SAL_CALL
XInteractionApproveImpl::queryInterface( const Type& rType )
    throw( RuntimeException )
{
    Any aRet = cppu::queryInterface(
        rType,
        SAL_STATIC_CAST( lang::XTypeProvider*, this ),
        SAL_STATIC_CAST( XInteractionApprove*,this) );
    return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
}

//////////////////////////////////////////////////////////////////////////////
//  XTypeProvider
//////////////////////////////////////////////////////////////////////////////

XTYPEPROVIDER_IMPL_2( XInteractionApproveImpl,
                      XTypeProvider,
                      XInteractionApprove )

void SAL_CALL XInteractionApproveImpl::select()
    throw (RuntimeException)
{
    m_bSelected = true;
}

bool XInteractionApproveImpl::isSelected() const
{
    return m_bSelected;
}

// XInteractionDisapproveImpl

XInteractionDisapproveImpl::XInteractionDisapproveImpl()
    : m_bSelected(false)
{
}

void SAL_CALL
XInteractionDisapproveImpl::acquire( void )
    throw()
{
    OWeakObject::acquire();
}

void SAL_CALL
XInteractionDisapproveImpl::release( void )
    throw()
{
    OWeakObject::release();
}

Any SAL_CALL
XInteractionDisapproveImpl::queryInterface( const Type& rType )
    throw( RuntimeException )
{
    Any aRet = cppu::queryInterface(
        rType,
        SAL_STATIC_CAST( lang::XTypeProvider*, this ),
        SAL_STATIC_CAST( XInteractionDisapprove*,this) );
    return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
}

//////////////////////////////////////////////////////////////////////////////
//  XTypeProvider
//////////////////////////////////////////////////////////////////////////////

XTYPEPROVIDER_IMPL_2( XInteractionDisapproveImpl,
                      XTypeProvider,
                      XInteractionDisapprove )

void SAL_CALL XInteractionDisapproveImpl::select()
    throw (RuntimeException)

{
    m_bSelected = true;
}

bool XInteractionDisapproveImpl::isSelected() const
{
    return m_bSelected;
}

// XInteractionRequestImpl

XInteractionRequestImpl::XInteractionRequestImpl(const rtl::OUString& aName)
    : p1( new XInteractionApproveImpl ),
      p2( new XInteractionDisapproveImpl ),
      m_aName(aName),
      m_aSeq( 2 )
{
    m_aSeq[0] = Reference<XInteractionContinuation>(p1);
    m_aSeq[1] = Reference<XInteractionContinuation>(p2);
}

void SAL_CALL
XInteractionRequestImpl::acquire( void )
    throw()
{
    OWeakObject::acquire();
}

void SAL_CALL
XInteractionRequestImpl::release( void )
    throw()
{
    OWeakObject::release();
}

Any SAL_CALL
XInteractionRequestImpl::queryInterface( const Type& rType )
    throw( RuntimeException )
{
    Any aRet = cppu::queryInterface(
        rType,
        SAL_STATIC_CAST( lang::XTypeProvider*, this ),
        SAL_STATIC_CAST( XInteractionRequest*,this) );
    return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
}

//////////////////////////////////////////////////////////////////////////////
//  XTypeProvider
/////////////////////////////////////////////////////////////////////////////

XTYPEPROVIDER_IMPL_2( XInteractionRequestImpl,
                      XTypeProvider,
                      XInteractionRequest )

Any SAL_CALL XInteractionRequestImpl::getRequest(  )
    throw (RuntimeException)
{
    Any aAny;
    UnsupportedNameClashException excep;
    excep.NameClash = NameClash::ERROR;
    aAny <<= excep;
    return aAny;
}

Sequence<Reference<XInteractionContinuation > > SAL_CALL
XInteractionRequestImpl::getContinuations(  )
    throw (RuntimeException)
{
    return m_aSeq;
}

bool XInteractionRequestImpl::aborted() const
{
    return p2->isSelected();
}

bool XInteractionRequestImpl::approved() const
{
    return p1->isSelected();
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */

#pragma once

#ifndef _LIBQI_QI_ATOMIC_HPP_
#define _LIBQI_QI_ATOMIC_HPP_

#ifdef _MSC_VER
# include <windows.h>
#endif

namespace qi
{
  template <typename T>
  class atomic
  {
  public:
    atomic()
      : _value(0)
    {
    }

    atomic(T value)
      : _value(value)
    {
    }

    /* prefix operators */
    T operator++();
    T operator--();

    T operator*()
    {
      return _value;
    }

  private:
    T _value;
  };

#ifdef __GNUC__
    template <typename T>
    T atomic<T>::operator++()
    {
      return __sync_add_and_fetch(&_value, 1);
    }

    template <typename T>
    T atomic<T>::operator--()
    {
      return __sync_sub_and_fetch(&_value, 1);
    }
#endif

#ifdef _MSC_VER
  template<>
  short atomic<short>::operator++()
  {
    return _InterlockedIncrement16(&_value);
  }

  template<>
  short atomic<short>::operator--()
  {
    return _InterlockedDecrement16(&_value);
  }

  template <>
  long atomic<long>::operator++()
  {
    return _InterlockedIncrement(&_value);
  }

  template <>
  long atomic<long>::operator--()
  {
    return _InterlockedDecrement(&_value);
  }
#endif
}

#endif // _LIBQI_QI_ATOMIC_HPP_
<commit_msg>Inline templates.<commit_after>/*
 * Copyright (c) 2012 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */

#pragma once

#ifndef _LIBQI_QI_ATOMIC_HPP_
#define _LIBQI_QI_ATOMIC_HPP_

#ifdef _MSC_VER
# include <windows.h>
#endif

#include <qi/config.hpp>

namespace qi
{
  template <typename T>
  class QI_API atomic
  {
  public:
    atomic()
      : _value(0)
    {
    }

    atomic(T value)
      : _value(value)
    {
    }

    /* prefix operators */
    T operator++();
    T operator--();

    T operator*()
    {
      return _value;
    }

  private:
    T _value;
  };

#ifdef __GNUC__
    template <typename T>
    T atomic<T>::operator++()
    {
      return __sync_add_and_fetch(&_value, 1);
    }

    template <typename T>
    T atomic<T>::operator--()
    {
      return __sync_sub_and_fetch(&_value, 1);
    }
#endif

#ifdef _MSC_VER
  template<>
  inline short atomic<short>::operator++()
  {
    return _InterlockedIncrement16(&_value);
  }

  template<>
  inline short atomic<short>::operator--()
  {
    return _InterlockedDecrement16(&_value);
  }

  template <>
  inline long atomic<long>::operator++()
  {
    return _InterlockedIncrement(&_value);
  }

  template <>
  inline long atomic<long>::operator--()
  {
    return _InterlockedDecrement(&_value);
  }
#endif
}

#endif // _LIBQI_QI_ATOMIC_HPP_
<|endoftext|>