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

#ifndef RMW_CONNEXT_SHARED_CPP__WAIT_HPP_
#define RMW_CONNEXT_SHARED_CPP__WAIT_HPP_

#include "ndds_include.hpp"

#include "rmw/error_handling.h"
#include "rmw/impl/cpp/macros.hpp"
#include "rmw/types.h"

#include "rmw_connext_shared_cpp/condition_error.hpp"
#include "rmw_connext_shared_cpp/types.hpp"
#include "rmw_connext_shared_cpp/visibility_control.h"

template<typename SubscriberInfo, typename ServiceInfo, typename ClientInfo>
rmw_ret_t
wait(
  const char * implementation_identifier,
  rmw_subscriptions_t * subscriptions,
  rmw_guard_conditions_t * guard_conditions,
  rmw_services_t * services,
  rmw_clients_t * clients,
  rmw_wait_set_t * wait_set,
  const rmw_time_t * wait_timeout)
{
  // To ensure that we properly clean up the wait set, we declare an
  // object whose destructor will detach what we attached (this was previously
  // being done inside the destructor of the wait set.
  struct atexit_t
  {
    ~atexit_t()
    {
      // Manually detach conditions and clear sequences, to ensure a clean wait set for next time.
      if (!wait_set) {
        RMW_SET_ERROR_MSG("wait set handle is null");
        return;
      }
      RMW_CHECK_TYPE_IDENTIFIERS_MATCH(
        wait set handle,
        wait_set->implementation_identifier, implementation_identifier,
        return )
      ConnextWaitSetInfo * wait_set_info = static_cast<ConnextWaitSetInfo *>(wait_set->data);
      if (!wait_set_info) {
        RMW_SET_ERROR_MSG("WaitSet implementation struct is null");
        return;
      }

      DDS::WaitSet * dds_wait_set = static_cast<DDS::WaitSet *>(wait_set_info->wait_set);
      if (!dds_wait_set) {
        RMW_SET_ERROR_MSG("DDS wait set handle is null");
        return;
      }

      DDS::ConditionSeq * attached_conditions =
        static_cast<DDSConditionSeq *>(wait_set_info->attached_conditions);
      if (!attached_conditions) {
        RMW_SET_ERROR_MSG("DDS condition sequence handle is null");
        return;
      }

      DDS::ReturnCode_t retcode;
      retcode = dds_wait_set->get_conditions(*attached_conditions);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get attached conditions for wait set");
        return;
      }

      for (DDS::Long i = 0; i < attached_conditions->length(); ++i) {
        retcode = dds_wait_set->detach_condition((*attached_conditions)[i]);
        if (retcode != DDS::RETCODE_OK) {
          RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        }
      }
    }
    rmw_wait_set_t * wait_set = NULL;
    const char * implementation_identifier = NULL;
  } atexit;

  atexit.wait_set = wait_set;
  atexit.implementation_identifier = implementation_identifier;

  if (!wait_set) {
    RMW_SET_ERROR_MSG("wait set handle is null");
    return RMW_RET_ERROR;
  }
  RMW_CHECK_TYPE_IDENTIFIERS_MATCH(
    wait set handle,
    wait_set->implementation_identifier, implementation_identifier,
    return RMW_RET_ERROR);

  ConnextWaitSetInfo * wait_set_info = static_cast<ConnextWaitSetInfo *>(wait_set->data);
  if (!wait_set_info) {
    RMW_SET_ERROR_MSG("WaitSet implementation struct is null");
    return RMW_RET_ERROR;
  }

  DDS::WaitSet * dds_wait_set = static_cast<DDS::WaitSet *>(wait_set_info->wait_set);
  if (!dds_wait_set) {
    RMW_SET_ERROR_MSG("DDS wait set handle is null");
    return RMW_RET_ERROR;
  }

  DDS::ConditionSeq * active_conditions =
    static_cast<DDS::ConditionSeq *>(wait_set_info->active_conditions);
  if (!active_conditions) {
    RMW_SET_ERROR_MSG("DDS condition sequence handle is null");
    return RMW_RET_ERROR;
  }

  // add a condition for each subscriber
  if (subscriptions) {
    for (size_t i = 0; i < subscriptions->subscriber_count; ++i) {
      SubscriberInfo * subscriber_info =
        static_cast<SubscriberInfo *>(subscriptions->subscribers[i]);
      if (!subscriber_info) {
        RMW_SET_ERROR_MSG("subscriber info handle is null");
        return RMW_RET_ERROR;
      }
      DDS::ReadCondition * read_condition = subscriber_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }
      rmw_ret_t rmw_status = check_attach_condition_error(
        dds_wait_set->attach_condition(read_condition));
      if (rmw_status != RMW_RET_OK) {
        return rmw_status;
      }
    }
  }

  // add a condition for each guard condition
  if (guard_conditions) {
    for (size_t i = 0; i < guard_conditions->guard_condition_count; ++i) {
      DDS::GuardCondition * guard_condition =
        static_cast<DDS::GuardCondition *>(guard_conditions->guard_conditions[i]);
      if (!guard_condition) {
        RMW_SET_ERROR_MSG("guard condition handle is null");
        return RMW_RET_ERROR;
      }
      rmw_ret_t rmw_status = check_attach_condition_error(
        dds_wait_set->attach_condition(guard_condition));
      if (rmw_status != RMW_RET_OK) {
        return rmw_status;
      }
    }
  }

  // add a condition for each service
  if (services) {
    for (size_t i = 0; i < services->service_count; ++i) {
      ServiceInfo * service_info =
        static_cast<ServiceInfo *>(services->services[i]);

      if (!service_info) {
        RMW_SET_ERROR_MSG("service info handle is null");
        return RMW_RET_ERROR;
      }

      DDS::ReadCondition * read_condition = service_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }
      rmw_ret_t rmw_status = check_attach_condition_error(
        dds_wait_set->attach_condition(read_condition));
      if (rmw_status != RMW_RET_OK) {
        return rmw_status;
      }
    }
  }

  // add a condition for each client
  if (clients) {
    for (size_t i = 0; i < clients->client_count; ++i) {
      ClientInfo * client_info =
        static_cast<ClientInfo *>(clients->clients[i]);
      if (!client_info) {
        RMW_SET_ERROR_MSG("client info handle is null");
        return RMW_RET_ERROR;
      }

      DDS::DataReader * response_datareader = client_info->response_datareader_;
      if (!response_datareader) {
        RMW_SET_ERROR_MSG("response datareader handle is null");
        return RMW_RET_ERROR;
      }

      // MIGHT BE IMPORTANT !!!
      DDS::ReadCondition * read_condition = client_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }
      rmw_ret_t rmw_status = check_attach_condition_error(
        dds_wait_set->attach_condition(read_condition));
      if (rmw_status != RMW_RET_OK) {
        return rmw_status;
      }
    }
  }

  // invoke wait until one of the conditions triggers
  DDS::Duration_t timeout;
  if (!wait_timeout) {
    timeout = DDS::DURATION_INFINITE;
  } else {
    timeout.sec = static_cast<DDS::Long>(wait_timeout->sec);
    timeout.nanosec = static_cast<DDS::Long>(wait_timeout->nsec);
  }

  DDS::ReturnCode_t status = dds_wait_set->wait(*active_conditions, timeout);

  if (status != DDS::RETCODE_OK && status != DDS::RETCODE_TIMEOUT) {
    RMW_SET_ERROR_MSG("failed to wait on wait set");
    return RMW_RET_ERROR;
  }

  // set subscriber handles to zero for all not triggered conditions
  if (subscriptions) {
    for (size_t i = 0; i < subscriptions->subscriber_count; ++i) {
      SubscriberInfo * subscriber_info =
        static_cast<SubscriberInfo *>(subscriptions->subscribers[i]);
      if (!subscriber_info) {
        RMW_SET_ERROR_MSG("subscriber info handle is null");
        return RMW_RET_ERROR;
      }
      DDS::ReadCondition * read_condition = subscriber_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }

      // search for subscriber condition in active set
      DDS::Long j = 0;
      for (; j < active_conditions->length(); ++j) {
        if ((*active_conditions)[j] == read_condition) {
          break;
        }
      }
      // if subscriber condition is not found in the active set
      // reset the subscriber handle
      if (!(j < active_conditions->length())) {
        subscriptions->subscribers[i] = 0;
      }
      DDS::ReturnCode_t retcode = dds_wait_set->detach_condition(read_condition);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        return RMW_RET_ERROR;
      }
    }
  }

  // set guard condition handles to zero for all not triggered conditions
  if (guard_conditions) {
    for (size_t i = 0; i < guard_conditions->guard_condition_count; ++i) {
      DDS::Condition * condition =
        static_cast<DDSCondition *>(guard_conditions->guard_conditions[i]);
      if (!condition) {
        RMW_SET_ERROR_MSG("condition handle is null");
        return RMW_RET_ERROR;
      }

      // search for guard condition in active set
      DDS::Long j = 0;
      for (; j < active_conditions->length(); ++j) {
        if ((*active_conditions)[j] == condition) {
          DDS::GuardCondition * guard = static_cast<DDS::GuardCondition *>(condition);
          DDS::ReturnCode_t status = guard->set_trigger_value(DDS::BOOLEAN_FALSE);
          if (status != DDS::RETCODE_OK) {
            RMW_SET_ERROR_MSG("failed to set trigger value");
            return RMW_RET_ERROR;
          }
          break;
        }
      }
      // if guard condition is not found in the active set
      // reset the guard handle
      if (!(j < active_conditions->length())) {
        guard_conditions->guard_conditions[i] = 0;
      }
      DDS::ReturnCode_t retcode = dds_wait_set->detach_condition(condition);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        return RMW_RET_ERROR;
      }
    }
  }

  // set service handles to zero for all not triggered conditions
  if (services) {
    for (size_t i = 0; i < services->service_count; ++i) {
      ServiceInfo * service_info =
        static_cast<ServiceInfo *>(services->services[i]);
      if (!service_info) {
        RMW_SET_ERROR_MSG("service info handle is null");
        return RMW_RET_ERROR;
      }
      DDS::ReadCondition * read_condition = service_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }

      // search for service condition in active set
      DDS::Long j = 0;
      for (; j < active_conditions->length(); ++j) {
        if ((*active_conditions)[j] == read_condition) {
          break;
        }
      }
      // if service condition is not found in the active set
      // reset the subscriber handle
      if (!(j < active_conditions->length())) {
        services->services[i] = 0;
      }
      DDS::ReturnCode_t retcode = dds_wait_set->detach_condition(read_condition);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        return RMW_RET_ERROR;
      }
    }
  }

  // set client handles to zero for all not triggered conditions
  if (clients) {
    for (size_t i = 0; i < clients->client_count; ++i) {
      ClientInfo * client_info =
        static_cast<ClientInfo *>(clients->clients[i]);
      if (!client_info) {
        RMW_SET_ERROR_MSG("client info handle is null");
        return RMW_RET_ERROR;
      }
      DDS::ReadCondition * read_condition = client_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }

      // search for service condition in active set
      DDS::Long j = 0;
      for (; j < active_conditions->length(); ++j) {
        if ((*active_conditions)[j] == read_condition) {
          break;
        }
      }
      // if client condition is not found in the active set
      // reset the subscriber handle
      if (!(j < active_conditions->length())) {
        clients->clients[i] = 0;
      }
      DDS::ReturnCode_t retcode = dds_wait_set->detach_condition(read_condition);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        return RMW_RET_ERROR;
      }
    }
  }

  if (status == DDS::RETCODE_TIMEOUT) {
    return RMW_RET_TIMEOUT;
  }
  return RMW_RET_OK;
}

#endif  // RMW_CONNEXT_SHARED_CPP__WAIT_HPP_
<commit_msg>Don't use DURATION_INFINITE, it is a RTI specific type (#335)<commit_after>// Copyright 2015-2017 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RMW_CONNEXT_SHARED_CPP__WAIT_HPP_
#define RMW_CONNEXT_SHARED_CPP__WAIT_HPP_

#include "ndds_include.hpp"

#include "rmw/error_handling.h"
#include "rmw/impl/cpp/macros.hpp"
#include "rmw/types.h"

#include "rmw_connext_shared_cpp/condition_error.hpp"
#include "rmw_connext_shared_cpp/types.hpp"
#include "rmw_connext_shared_cpp/visibility_control.h"

template<typename SubscriberInfo, typename ServiceInfo, typename ClientInfo>
rmw_ret_t
wait(
  const char * implementation_identifier,
  rmw_subscriptions_t * subscriptions,
  rmw_guard_conditions_t * guard_conditions,
  rmw_services_t * services,
  rmw_clients_t * clients,
  rmw_wait_set_t * wait_set,
  const rmw_time_t * wait_timeout)
{
  // To ensure that we properly clean up the wait set, we declare an
  // object whose destructor will detach what we attached (this was previously
  // being done inside the destructor of the wait set.
  struct atexit_t
  {
    ~atexit_t()
    {
      // Manually detach conditions and clear sequences, to ensure a clean wait set for next time.
      if (!wait_set) {
        RMW_SET_ERROR_MSG("wait set handle is null");
        return;
      }
      RMW_CHECK_TYPE_IDENTIFIERS_MATCH(
        wait set handle,
        wait_set->implementation_identifier, implementation_identifier,
        return )
      ConnextWaitSetInfo * wait_set_info = static_cast<ConnextWaitSetInfo *>(wait_set->data);
      if (!wait_set_info) {
        RMW_SET_ERROR_MSG("WaitSet implementation struct is null");
        return;
      }

      DDS::WaitSet * dds_wait_set = static_cast<DDS::WaitSet *>(wait_set_info->wait_set);
      if (!dds_wait_set) {
        RMW_SET_ERROR_MSG("DDS wait set handle is null");
        return;
      }

      DDS::ConditionSeq * attached_conditions =
        static_cast<DDSConditionSeq *>(wait_set_info->attached_conditions);
      if (!attached_conditions) {
        RMW_SET_ERROR_MSG("DDS condition sequence handle is null");
        return;
      }

      DDS::ReturnCode_t retcode;
      retcode = dds_wait_set->get_conditions(*attached_conditions);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get attached conditions for wait set");
        return;
      }

      for (DDS::Long i = 0; i < attached_conditions->length(); ++i) {
        retcode = dds_wait_set->detach_condition((*attached_conditions)[i]);
        if (retcode != DDS::RETCODE_OK) {
          RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        }
      }
    }
    rmw_wait_set_t * wait_set = NULL;
    const char * implementation_identifier = NULL;
  } atexit;

  atexit.wait_set = wait_set;
  atexit.implementation_identifier = implementation_identifier;

  if (!wait_set) {
    RMW_SET_ERROR_MSG("wait set handle is null");
    return RMW_RET_ERROR;
  }
  RMW_CHECK_TYPE_IDENTIFIERS_MATCH(
    wait set handle,
    wait_set->implementation_identifier, implementation_identifier,
    return RMW_RET_ERROR);

  ConnextWaitSetInfo * wait_set_info = static_cast<ConnextWaitSetInfo *>(wait_set->data);
  if (!wait_set_info) {
    RMW_SET_ERROR_MSG("WaitSet implementation struct is null");
    return RMW_RET_ERROR;
  }

  DDS::WaitSet * dds_wait_set = static_cast<DDS::WaitSet *>(wait_set_info->wait_set);
  if (!dds_wait_set) {
    RMW_SET_ERROR_MSG("DDS wait set handle is null");
    return RMW_RET_ERROR;
  }

  DDS::ConditionSeq * active_conditions =
    static_cast<DDS::ConditionSeq *>(wait_set_info->active_conditions);
  if (!active_conditions) {
    RMW_SET_ERROR_MSG("DDS condition sequence handle is null");
    return RMW_RET_ERROR;
  }

  // add a condition for each subscriber
  if (subscriptions) {
    for (size_t i = 0; i < subscriptions->subscriber_count; ++i) {
      SubscriberInfo * subscriber_info =
        static_cast<SubscriberInfo *>(subscriptions->subscribers[i]);
      if (!subscriber_info) {
        RMW_SET_ERROR_MSG("subscriber info handle is null");
        return RMW_RET_ERROR;
      }
      DDS::ReadCondition * read_condition = subscriber_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }
      rmw_ret_t rmw_status = check_attach_condition_error(
        dds_wait_set->attach_condition(read_condition));
      if (rmw_status != RMW_RET_OK) {
        return rmw_status;
      }
    }
  }

  // add a condition for each guard condition
  if (guard_conditions) {
    for (size_t i = 0; i < guard_conditions->guard_condition_count; ++i) {
      DDS::GuardCondition * guard_condition =
        static_cast<DDS::GuardCondition *>(guard_conditions->guard_conditions[i]);
      if (!guard_condition) {
        RMW_SET_ERROR_MSG("guard condition handle is null");
        return RMW_RET_ERROR;
      }
      rmw_ret_t rmw_status = check_attach_condition_error(
        dds_wait_set->attach_condition(guard_condition));
      if (rmw_status != RMW_RET_OK) {
        return rmw_status;
      }
    }
  }

  // add a condition for each service
  if (services) {
    for (size_t i = 0; i < services->service_count; ++i) {
      ServiceInfo * service_info =
        static_cast<ServiceInfo *>(services->services[i]);

      if (!service_info) {
        RMW_SET_ERROR_MSG("service info handle is null");
        return RMW_RET_ERROR;
      }

      DDS::ReadCondition * read_condition = service_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }
      rmw_ret_t rmw_status = check_attach_condition_error(
        dds_wait_set->attach_condition(read_condition));
      if (rmw_status != RMW_RET_OK) {
        return rmw_status;
      }
    }
  }

  // add a condition for each client
  if (clients) {
    for (size_t i = 0; i < clients->client_count; ++i) {
      ClientInfo * client_info =
        static_cast<ClientInfo *>(clients->clients[i]);
      if (!client_info) {
        RMW_SET_ERROR_MSG("client info handle is null");
        return RMW_RET_ERROR;
      }

      DDS::DataReader * response_datareader = client_info->response_datareader_;
      if (!response_datareader) {
        RMW_SET_ERROR_MSG("response datareader handle is null");
        return RMW_RET_ERROR;
      }

      // MIGHT BE IMPORTANT !!!
      DDS::ReadCondition * read_condition = client_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }
      rmw_ret_t rmw_status = check_attach_condition_error(
        dds_wait_set->attach_condition(read_condition));
      if (rmw_status != RMW_RET_OK) {
        return rmw_status;
      }
    }
  }

  // invoke wait until one of the conditions triggers
  DDS::Duration_t timeout;
  if (!wait_timeout) {
    timeout.sec = DDS::DURATION_INFINITE_SEC;
    timeout.nanosec = DDS::DURATION_INFINITE_NSEC;
  } else {
    timeout.sec = static_cast<DDS::Long>(wait_timeout->sec);
    timeout.nanosec = static_cast<DDS::Long>(wait_timeout->nsec);
  }

  DDS::ReturnCode_t status = dds_wait_set->wait(*active_conditions, timeout);

  if (status != DDS::RETCODE_OK && status != DDS::RETCODE_TIMEOUT) {
    RMW_SET_ERROR_MSG("failed to wait on wait set");
    return RMW_RET_ERROR;
  }

  // set subscriber handles to zero for all not triggered conditions
  if (subscriptions) {
    for (size_t i = 0; i < subscriptions->subscriber_count; ++i) {
      SubscriberInfo * subscriber_info =
        static_cast<SubscriberInfo *>(subscriptions->subscribers[i]);
      if (!subscriber_info) {
        RMW_SET_ERROR_MSG("subscriber info handle is null");
        return RMW_RET_ERROR;
      }
      DDS::ReadCondition * read_condition = subscriber_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }

      // search for subscriber condition in active set
      DDS::Long j = 0;
      for (; j < active_conditions->length(); ++j) {
        if ((*active_conditions)[j] == read_condition) {
          break;
        }
      }
      // if subscriber condition is not found in the active set
      // reset the subscriber handle
      if (!(j < active_conditions->length())) {
        subscriptions->subscribers[i] = 0;
      }
      DDS::ReturnCode_t retcode = dds_wait_set->detach_condition(read_condition);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        return RMW_RET_ERROR;
      }
    }
  }

  // set guard condition handles to zero for all not triggered conditions
  if (guard_conditions) {
    for (size_t i = 0; i < guard_conditions->guard_condition_count; ++i) {
      DDS::Condition * condition =
        static_cast<DDSCondition *>(guard_conditions->guard_conditions[i]);
      if (!condition) {
        RMW_SET_ERROR_MSG("condition handle is null");
        return RMW_RET_ERROR;
      }

      // search for guard condition in active set
      DDS::Long j = 0;
      for (; j < active_conditions->length(); ++j) {
        if ((*active_conditions)[j] == condition) {
          DDS::GuardCondition * guard = static_cast<DDS::GuardCondition *>(condition);
          DDS::ReturnCode_t status = guard->set_trigger_value(DDS::BOOLEAN_FALSE);
          if (status != DDS::RETCODE_OK) {
            RMW_SET_ERROR_MSG("failed to set trigger value");
            return RMW_RET_ERROR;
          }
          break;
        }
      }
      // if guard condition is not found in the active set
      // reset the guard handle
      if (!(j < active_conditions->length())) {
        guard_conditions->guard_conditions[i] = 0;
      }
      DDS::ReturnCode_t retcode = dds_wait_set->detach_condition(condition);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        return RMW_RET_ERROR;
      }
    }
  }

  // set service handles to zero for all not triggered conditions
  if (services) {
    for (size_t i = 0; i < services->service_count; ++i) {
      ServiceInfo * service_info =
        static_cast<ServiceInfo *>(services->services[i]);
      if (!service_info) {
        RMW_SET_ERROR_MSG("service info handle is null");
        return RMW_RET_ERROR;
      }
      DDS::ReadCondition * read_condition = service_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }

      // search for service condition in active set
      DDS::Long j = 0;
      for (; j < active_conditions->length(); ++j) {
        if ((*active_conditions)[j] == read_condition) {
          break;
        }
      }
      // if service condition is not found in the active set
      // reset the subscriber handle
      if (!(j < active_conditions->length())) {
        services->services[i] = 0;
      }
      DDS::ReturnCode_t retcode = dds_wait_set->detach_condition(read_condition);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        return RMW_RET_ERROR;
      }
    }
  }

  // set client handles to zero for all not triggered conditions
  if (clients) {
    for (size_t i = 0; i < clients->client_count; ++i) {
      ClientInfo * client_info =
        static_cast<ClientInfo *>(clients->clients[i]);
      if (!client_info) {
        RMW_SET_ERROR_MSG("client info handle is null");
        return RMW_RET_ERROR;
      }
      DDS::ReadCondition * read_condition = client_info->read_condition_;
      if (!read_condition) {
        RMW_SET_ERROR_MSG("read condition handle is null");
        return RMW_RET_ERROR;
      }

      // search for service condition in active set
      DDS::Long j = 0;
      for (; j < active_conditions->length(); ++j) {
        if ((*active_conditions)[j] == read_condition) {
          break;
        }
      }
      // if client condition is not found in the active set
      // reset the subscriber handle
      if (!(j < active_conditions->length())) {
        clients->clients[i] = 0;
      }
      DDS::ReturnCode_t retcode = dds_wait_set->detach_condition(read_condition);
      if (retcode != DDS::RETCODE_OK) {
        RMW_SET_ERROR_MSG("Failed to get detach condition from wait set");
        return RMW_RET_ERROR;
      }
    }
  }

  if (status == DDS::RETCODE_TIMEOUT) {
    return RMW_RET_TIMEOUT;
  }
  return RMW_RET_OK;
}

#endif  // RMW_CONNEXT_SHARED_CPP__WAIT_HPP_
<|endoftext|>


<commit_before>// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// 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 "iceoryx_posh/iceoryx_posh_types.hpp"
#include "iceoryx_posh/internal/mepoo/memory_manager.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_data.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_popper.hpp"
#include "iceoryx_posh/internal/popo/ports/subscriber_port_data.hpp"
#include "iceoryx_posh/internal/popo/ports/subscriber_port_multi_producer.hpp"
#include "iceoryx_posh/internal/popo/ports/subscriber_port_single_producer.hpp"
#include "iceoryx_posh/internal/popo/ports/subscriber_port_user.hpp"

#include "iceoryx_posh/mepoo/mepoo_config.hpp"
#include "iceoryx_utils/error_handling/error_handling.hpp"
#include "iceoryx_utils/internal/posix_wrapper/shared_memory_object/allocator.hpp"
#include "test.hpp"

#include <memory>

using namespace ::testing;

struct DummySample
{
    uint64_t dummy{42};
};

class SubscriberPort_test : public Test
{
  protected:
    SubscriberPort_test()
    {
        m_mempoolconf.addMemPool({CHUNK_SIZE, NUM_CHUNKS_IN_POOL});
        m_memoryManager.configureMemoryManager(m_mempoolconf, &m_memoryAllocator, &m_memoryAllocator);
    }

    ~SubscriberPort_test()
    {
    }

    void SetUp()
    {
    }

    void TearDown()
    {
    }

    static constexpr size_t MEMORY_SIZE = 1024 * 1024;
    uint8_t m_memory[MEMORY_SIZE];
    static constexpr uint32_t NUM_CHUNKS_IN_POOL = 20;
    static constexpr uint32_t CHUNK_SIZE = 128;

    iox::posix::Allocator m_memoryAllocator{m_memory, MEMORY_SIZE};
    iox::mepoo::MePooConfig m_mempoolconf;
    iox::mepoo::MemoryManager m_memoryManager;

    iox::popo::SubscriberPortData m_subscriberPortDataSingleProducer{
        iox::capro::ServiceDescription("x", "y", "z"),
        "myApp",
        iox::cxx::VariantQueueTypes::SoFi_SingleProducerSingleConsumer};
    iox::popo::SubscriberPortUser m_sutUserSideSingleProducer{&m_subscriberPortDataSingleProducer};
    iox::popo::SubscriberPortSingleProducer m_sutRouDiSideSingleProducer{&m_subscriberPortDataSingleProducer};
};

TEST_F(SubscriberPort_test, initialStateNotSubscribed)
{
    EXPECT_THAT(m_sutUserSideSingleProducer.getSubscriptionState(), Eq(iox::SubscribeState::NOT_SUBSCRIBED));
}

TEST_F(SubscriberPort_test, initialStateNoChunksAvailable)
{
    auto maybeChunk = m_sutUserSideSingleProducer.getChunk();

    EXPECT_FALSE(maybeChunk.has_error());
    EXPECT_FALSE(maybeChunk.get_value().has_value());
    EXPECT_FALSE(m_sutUserSideSingleProducer.hasNewChunks());
}

TEST_F(SubscriberPort_test, initialStateNoChunksLost)
{
    EXPECT_FALSE(m_sutUserSideSingleProducer.hasLostChunks());
}

TEST_F(SubscriberPort_test, initialStateReturnsNoCaProMessage)
{
    auto maybeCaproMessage = m_sutRouDiSideSingleProducer.getCaProMessage();

    EXPECT_FALSE(maybeCaproMessage.has_value());
}

TEST_F(SubscriberPort_test, subscribeCallResultsInSUBCaProMessage)
{
    m_sutUserSideSingleProducer.subscribe();

    auto maybeCaproMessage = m_sutRouDiSideSingleProducer.getCaProMessage();

    EXPECT_TRUE(maybeCaproMessage.has_value());
    auto caproMessage = maybeCaproMessage.value();
    EXPECT_THAT(caproMessage.m_type, Eq(iox::capro::CaproMessageType::SUB));
    EXPECT_THAT(caproMessage.m_serviceDescription, Eq(iox::capro::ServiceDescription("x", "y", "z")));
    EXPECT_THAT(caproMessage.m_historyCapacity, Eq(0u));
}

TEST_F(SubscriberPort_test, subscribeRequestedWhenCallingSubscribe)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::SUBSCRIBE_REQUESTED));
}<commit_msg>iox-#25: tests for discovery state machine of subscriber port<commit_after>// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// 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 "iceoryx_posh/iceoryx_posh_types.hpp"
#include "iceoryx_posh/internal/mepoo/memory_manager.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_data.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/chunk_queue_popper.hpp"
#include "iceoryx_posh/internal/popo/ports/subscriber_port_data.hpp"
#include "iceoryx_posh/internal/popo/ports/subscriber_port_multi_producer.hpp"
#include "iceoryx_posh/internal/popo/ports/subscriber_port_single_producer.hpp"
#include "iceoryx_posh/internal/popo/ports/subscriber_port_user.hpp"

#include "iceoryx_posh/mepoo/mepoo_config.hpp"
#include "iceoryx_utils/error_handling/error_handling.hpp"
#include "iceoryx_utils/internal/posix_wrapper/shared_memory_object/allocator.hpp"
#include "test.hpp"

#include <memory>

using namespace ::testing;

class SubscriberPort_test : public Test
{
  protected:
    SubscriberPort_test()
    {
    }

    ~SubscriberPort_test()
    {
    }

    void SetUp()
    {
    }

    void TearDown()
    {
    }

    iox::popo::SubscriberPortData m_subscriberPortDataSingleProducer{
        iox::capro::ServiceDescription("x", "y", "z"),
        "myApp",
        iox::cxx::VariantQueueTypes::SoFi_SingleProducerSingleConsumer};
    iox::popo::SubscriberPortUser m_sutUserSideSingleProducer{&m_subscriberPortDataSingleProducer};
    iox::popo::SubscriberPortSingleProducer m_sutRouDiSideSingleProducer{&m_subscriberPortDataSingleProducer};
};

TEST_F(SubscriberPort_test, initialStateNotSubscribed)
{
    EXPECT_THAT(m_sutUserSideSingleProducer.getSubscriptionState(), Eq(iox::SubscribeState::NOT_SUBSCRIBED));
}

TEST_F(SubscriberPort_test, initialStateNoChunksAvailable)
{
    auto maybeChunk = m_sutUserSideSingleProducer.getChunk();

    EXPECT_FALSE(maybeChunk.has_error());
    EXPECT_FALSE(maybeChunk.get_value().has_value());
    EXPECT_FALSE(m_sutUserSideSingleProducer.hasNewChunks());
}

TEST_F(SubscriberPort_test, initialStateNoChunksLost)
{
    EXPECT_FALSE(m_sutUserSideSingleProducer.hasLostChunks());
}

TEST_F(SubscriberPort_test, initialStateReturnsNoCaProMessage)
{
    auto maybeCaproMessage = m_sutRouDiSideSingleProducer.getCaProMessage();

    EXPECT_FALSE(maybeCaproMessage.has_value());
}

TEST_F(SubscriberPort_test, subscribeCallResultsInSubCaProMessage)
{
    m_sutUserSideSingleProducer.subscribe();

    auto maybeCaproMessage = m_sutRouDiSideSingleProducer.getCaProMessage();

    EXPECT_TRUE(maybeCaproMessage.has_value());
    auto caproMessage = maybeCaproMessage.value();
    EXPECT_THAT(caproMessage.m_type, Eq(iox::capro::CaproMessageType::SUB));
    EXPECT_THAT(caproMessage.m_serviceDescription, Eq(iox::capro::ServiceDescription("x", "y", "z")));
    EXPECT_THAT(caproMessage.m_historyCapacity, Eq(0u));
}

TEST_F(SubscriberPort_test, subscribeRequestedWhenCallingSubscribe)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::SUBSCRIBE_REQUESTED));
}

TEST_F(SubscriberPort_test, nackResponseOnSubResultsInWaitForOffer)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::NACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::WAIT_FOR_OFFER));
}

TEST_F(SubscriberPort_test, ackResponseOnSubResultsInSubscribed)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::ACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::SUBSCRIBED));
}

TEST_F(SubscriberPort_test, offerInWaitForOfferTriggersSubMessage)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::NACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);
    caproMessage.m_type = iox::capro::CaproMessageType::OFFER;

    auto maybeCaproMessage = m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);

    EXPECT_TRUE(maybeCaproMessage.has_value());
    auto caproMessageResponse = maybeCaproMessage.value();
    EXPECT_THAT(caproMessageResponse.m_type, Eq(iox::capro::CaproMessageType::SUB));
    EXPECT_THAT(caproMessageResponse.m_serviceDescription, Eq(iox::capro::ServiceDescription("x", "y", "z")));
    EXPECT_THAT(caproMessageResponse.m_historyCapacity, Eq(0u));
}

TEST_F(SubscriberPort_test, offerInWaitForOfferResultsInSubscribeRequested)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::NACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);
    caproMessage.m_type = iox::capro::CaproMessageType::OFFER;
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::SUBSCRIBE_REQUESTED));
}

TEST_F(SubscriberPort_test, unsubscribeInWaitForOfferResultsInNotSubscribed)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::NACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);
    m_sutUserSideSingleProducer.unsubscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::NOT_SUBSCRIBED));
}

TEST_F(SubscriberPort_test, StopOfferInSubscribedResultsInWaitForOffer)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::ACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);
    caproMessage.m_type = iox::capro::CaproMessageType::STOP_OFFER;
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::WAIT_FOR_OFFER));
}

TEST_F(SubscriberPort_test, unsubscribeInSubscribedTriggersUnsubMessage)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::ACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);
    m_sutUserSideSingleProducer.unsubscribe();

    auto maybeCaproMessage = m_sutRouDiSideSingleProducer.getCaProMessage();

    EXPECT_TRUE(maybeCaproMessage.has_value());
    auto caproMessageResponse = maybeCaproMessage.value();
    EXPECT_THAT(caproMessageResponse.m_type, Eq(iox::capro::CaproMessageType::UNSUB));
    EXPECT_THAT(caproMessageResponse.m_serviceDescription, Eq(iox::capro::ServiceDescription("x", "y", "z")));
}

TEST_F(SubscriberPort_test, unsubscribeInSubscribedResultsInUnsubscribeRequested)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::ACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);
    m_sutUserSideSingleProducer.unsubscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::UNSUBSCRIBE_REQUESTED));
}

TEST_F(SubscriberPort_test, ackInUnsubscribeRequestedResultsInNotSubscribed)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::ACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);
    m_sutUserSideSingleProducer.unsubscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::NOT_SUBSCRIBED));
}

TEST_F(SubscriberPort_test, nackInUnsubscribeRequestedResultsInNotSubscribed)
{
    m_sutUserSideSingleProducer.subscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::ACK,
                                          iox::capro::ServiceDescription("x", "y", "z"));
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);
    m_sutUserSideSingleProducer.unsubscribe();
    m_sutRouDiSideSingleProducer.getCaProMessage(); // only RouDi changes state
    caproMessage.m_type = iox::capro::CaproMessageType::NACK;
    m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);

    const auto subscriptionState = m_sutUserSideSingleProducer.getSubscriptionState();

    EXPECT_THAT(subscriptionState, Eq(iox::SubscribeState::NOT_SUBSCRIBED));
}

TEST_F(SubscriberPort_test, invalidMessageResultsInError)
{
    auto errorHandlerCalled{false};
    auto errorHandlerGuard = iox::ErrorHandler::SetTemporaryErrorHandler([&errorHandlerCalled](
        const iox::Error, const std::function<void()>, const iox::ErrorLevel) { errorHandlerCalled = true; });
    iox::capro::CaproMessage caproMessage(iox::capro::CaproMessageType::SUB,
                                          iox::capro::ServiceDescription("x", "y", "z"));

    auto maybeCaproMessage = m_sutRouDiSideSingleProducer.dispatchCaProMessage(caproMessage);

    EXPECT_FALSE(maybeCaproMessage.has_value());
    EXPECT_TRUE(errorHandlerCalled);
}<|endoftext|>


<commit_before>#include	"FTFace.h"
#include	"FTFont.h"
#include	"FTGlyphContainer.h"
#include	"FTGlyph.h" // for FTBbox
#include	"FTGL.h"

FTFont::FTFont()
:	numFaces(0),
	glyphList(0),
	numGlyphs(0),
	preCache(true),
	err(0)
{
	pen.x = 0;
	pen.y = 0;
}

FTFont::~FTFont()
{
	Close();
}

bool FTFont::Open( const char* fontname, bool p)
{
	preCache = p;

	if( face.Open( fontname))
	{
		FT_Face* ftFace = face.Face();
		numGlyphs = (*ftFace)->num_glyphs;

		return true;
	}
	else
	{
		err = face.Error();
		return false;
	}
}

void FTFont::Close()
{
	delete glyphList;
}

bool FTFont::FaceSize( const unsigned int size, const unsigned int res )
{
	charSize = face.Size( size, res);

	if( glyphList)
		delete glyphList;

	glyphList = new FTGlyphContainer( &face, numGlyphs, preCache);

	if( MakeGlyphList())
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool FTFont::MakeGlyphList()
{
	for( unsigned int c = 0; c < numGlyphs; ++c)
	{
		if( preCache)
		{
			glyphList->Add( MakeGlyph( c), c);
		}
		else
		{
			glyphList->Add( NULL, c);
		}
	}

	return !err;
}

bool FTFont::CharMap( FT_Encoding encoding)
{
	err = face.CharMap( encoding);
	return !err;
}

int	FTFont::Ascender() const
{
	return charSize.Ascender();
}

int	FTFont::Descender() const
{
	return charSize.Descender();
}

void FTFont::BBox( const char* string,
                   int& llx, int& lly, int& llz, int& urx, int& ury, int& urz)
{
	const unsigned char* c = (unsigned char*)string; // This is ugly, what is the c++ way?
	llx = lly = llz = urx = ury = urz = 0;
	FTBBox bbox;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		bbox = glyphList->BBox( *c);

		// Lower extent
		lly = lly < bbox.y1 ? lly: bbox.y1;
		// Upper extent
		ury = ury > bbox.y2 ? ury: bbox.y2;
		// Depth
		urz = urz < bbox.z2 ? urz: bbox.z2;

		// Width
		urx += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	//Final adjustments
	llx = glyphList->BBox( *string).x1;
	urx -= glyphList->Advance( *(c - 1), 0);
	urx += bbox.x2;

}

void FTFont::BBox( const wchar_t* string,
                   int& llx, int& lly, int& llz, int& urx, int& ury, int& urz)
{
	const wchar_t* c = string; // wchar_t IS unsigned?
	llx = lly = llz = urx = ury = urz = 0;
	FTBBox bbox;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		bbox = glyphList->BBox( *c);

		// Lower extent
		lly = lly < bbox.y1 ? lly: bbox.y1;
		// Upper extent
		ury = ury > bbox.y2 ? ury: bbox.y2;
		// Depth
		urz = urz < bbox.z2 ? urz: bbox.z2;

		// Width
		urx += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	//Final adjustments
	llx = glyphList->BBox( *string).x1;
	urx -= glyphList->Advance( *(c - 1), 0);
	urx += bbox.x2;

}

float FTFont::Advance( const wchar_t* string)
{
	const wchar_t* c = string; // wchar_t IS unsigned?
	float width = 0;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		width += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	return width;
}

float FTFont::Advance( const char* string)
{
	const unsigned char* c = (unsigned char*)string; // This is ugly, what is the c++ way?
	float width = 0;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		width += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	return width;
}

void FTFont::render( const char* string )
{
	const unsigned char* c = (unsigned char*)string; // This is ugly, what is the c++ way?
	FT_Vector kernAdvance;
	pen.x = 0; pen.y = 0;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		kernAdvance = glyphList->render( *c, *(c + 1), pen);

		pen.x += kernAdvance.x;
		pen.y += kernAdvance.y;
		++c;
	}
}

void FTFont::render( const wchar_t* string )
{
	const wchar_t* c = string; // wchar_t IS unsigned?
	FT_Vector kernAdvance;
	pen.x = 0; pen.y = 0;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		kernAdvance = glyphList->render( *c, *(c + 1), pen);

		pen.x += kernAdvance.x;
		pen.y += kernAdvance.y;
		++c;
	}
}

<commit_msg>fix me<commit_after>#include	"FTFace.h"
#include	"FTFont.h"
#include	"FTGlyphContainer.h"
#include	"FTGlyph.h" // for FTBbox
#include	"FTGL.h"

//#include "mmgr.h"

FTFont::FTFont()
:	numFaces(0),
	glyphList(0),
	numGlyphs(0),
	preCache(true),
	err(0)
{
	pen.x = 0;
	pen.y = 0;
}

FTFont::~FTFont()
{
	Close();
}

bool FTFont::Open( const char* fontname, bool p)
{
	preCache = p;

	if( face.Open( fontname))
	{
		FT_Face* ftFace = face.Face();
		numGlyphs = (*ftFace)->num_glyphs;

		return true;
	}
	else
	{
		err = face.Error();
		return false;
	}
}

void FTFont::Close()
{
	delete glyphList;
}

bool FTFont::FaceSize( const unsigned int size, const unsigned int res )
{
	charSize = face.Size( size, res);

	if( glyphList)
		delete glyphList;

	glyphList = new FTGlyphContainer( &face, numGlyphs, preCache);

	if( MakeGlyphList())
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool FTFont::MakeGlyphList()
{
	for( unsigned int c = 0; c < numGlyphs; ++c)
	{
		if( preCache)
		{
			glyphList->Add( MakeGlyph( c), c);
		}
		else
		{
			glyphList->Add( NULL, c);
		}
	}

	return !err; // FIXME what err?
}

bool FTFont::CharMap( FT_Encoding encoding)
{
	err = face.CharMap( encoding);
	return !err;
}

int	FTFont::Ascender() const
{
	return charSize.Ascender();
}

int	FTFont::Descender() const
{
	return charSize.Descender();
}

void FTFont::BBox( const char* string,
                   int& llx, int& lly, int& llz, int& urx, int& ury, int& urz)
{
	const unsigned char* c = (unsigned char*)string; // This is ugly, what is the c++ way?
	llx = lly = llz = urx = ury = urz = 0;
	FTBBox bbox;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		bbox = glyphList->BBox( *c);

		// Lower extent
		lly = lly < bbox.y1 ? lly: bbox.y1;
		// Upper extent
		ury = ury > bbox.y2 ? ury: bbox.y2;
		// Depth
		urz = urz < bbox.z2 ? urz: bbox.z2;

		// Width
		urx += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	//Final adjustments
	llx = glyphList->BBox( *string).x1;
	urx -= glyphList->Advance( *(c - 1), 0);
	urx += bbox.x2;

}

void FTFont::BBox( const wchar_t* string,
                   int& llx, int& lly, int& llz, int& urx, int& ury, int& urz)
{
	const wchar_t* c = string; // wchar_t IS unsigned?
	llx = lly = llz = urx = ury = urz = 0;
	FTBBox bbox;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		bbox = glyphList->BBox( *c);

		// Lower extent
		lly = lly < bbox.y1 ? lly: bbox.y1;
		// Upper extent
		ury = ury > bbox.y2 ? ury: bbox.y2;
		// Depth
		urz = urz < bbox.z2 ? urz: bbox.z2;

		// Width
		urx += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	//Final adjustments
	llx = glyphList->BBox( *string).x1;
	urx -= glyphList->Advance( *(c - 1), 0);
	urx += bbox.x2;

}

float FTFont::Advance( const wchar_t* string)
{
	const wchar_t* c = string; // wchar_t IS unsigned?
	float width = 0;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		width += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	return width;
}

float FTFont::Advance( const char* string)
{
	const unsigned char* c = (unsigned char*)string; // This is ugly, what is the c++ way?
	float width = 0;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		width += glyphList->Advance( *c, *(c + 1));
		++c;
	}

	return width;
}

void FTFont::render( const char* string )
{
	const unsigned char* c = (unsigned char*)string; // This is ugly, what is the c++ way?
	FT_Vector kernAdvance;
	pen.x = 0; pen.y = 0;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		kernAdvance = glyphList->render( *c, *(c + 1), pen);

		pen.x += kernAdvance.x;
		pen.y += kernAdvance.y;
		++c;
	}
}

void FTFont::render( const wchar_t* string )
{
	const wchar_t* c = string; // wchar_t IS unsigned?
	FT_Vector kernAdvance;
	pen.x = 0; pen.y = 0;

	while( *c)
	{
		if( !glyphList->Glyph( static_cast<unsigned int>(*c)))
		{
			unsigned int g = face.CharIndex( static_cast<unsigned int>(*c));
			glyphList->Add( MakeGlyph( g), g);
		}

		kernAdvance = glyphList->render( *c, *(c + 1), pen);

		pen.x += kernAdvance.x;
		pen.y += kernAdvance.y;
		++c;
	}
}

<|endoftext|>


<commit_before>/**
 * Copyright 2008 Matthew Graham
 * 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 "snapl/client.h"
#include "snapl/command.h"
#include "snapl/message.h"
#include "snapl/net/connection.h"

using namespace snapl;

client_c::client_c()
: m_connection( NULL )
{}

client_c::client_c( connection_i &conn )
: m_connection( &conn )
{}

void client_c::send_request( command_c &cmd )
{
	// send_message( cmd.command_request() );
	// message_queue_i &queue( m_factory.message() );
	// queue.
	if ( ! m_connection )
		return;

	message_c msg;
	cmd.get_request( msg );
	m_connection->write_line( msg.arg_string() );
	// writing content in a request will come in a later iteration
}

void client_c::wait_for_response( command_c &cmd )
{
	std::string response_line;
	m_connection->read_line( response_line );
	message_c msg( response_line );
	// reading body from a response will come in a later iteration
	if ( ! cmd.set_response(msg) ) {
		std::cerr << "error parsing response\n";
	}
}

<commit_msg>improved reporting for client msg parsing errors<commit_after>/**
 * Copyright 2008 Matthew Graham
 * 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 "snapl/client.h"
#include "snapl/command.h"
#include "snapl/message.h"
#include "snapl/net/connection.h"

using namespace snapl;

client_c::client_c()
: m_connection( NULL )
{}

client_c::client_c( connection_i &conn )
: m_connection( &conn )
{}

void client_c::send_request( command_c &cmd )
{
	// send_message( cmd.command_request() );
	// message_queue_i &queue( m_factory.message() );
	// queue.
	if ( ! m_connection )
		return;

	message_c msg;
	cmd.get_request( msg );
	m_connection->write_line( msg.arg_string() );
	// writing content in a request will come in a later iteration
}

void client_c::wait_for_response( command_c &cmd )
{
	std::string response_line;
	m_connection->read_line( response_line );
	message_c msg( response_line );
	// reading body from a response will come in a later iteration
	if ( ! cmd.set_response(msg) ) {
		std::cerr << "error parsing response("
			<< response_line << ")\n";
	}
}

<|endoftext|>


<commit_before>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string>
#include <cctype>
#include <iostream>

#include "common.hxx"

using namespace std;

namespace tglng {
  bool parseInteger(signed& dst, const wstring& str,
                    unsigned offset, unsigned* end) {
    unsigned ix = offset;
    bool negative = false;
    unsigned base = 10;

    dst = 0;

    //Skip leading whitespace
    while (ix < str.size() && iswspace(str[ix]))
      ++ix;

    //If hit EOI, reject
    if (ix >= str.size()) {
      if (end) *end = ix;
      return false;
    }

    //Leading sign
    if (str[ix] == L'+') ++ix;
    else if (str[ix] == L'-') {
      ++ix;
      negative = true;
    }

    if (ix >= str.size()) {
      if (end) *end = ix;
      return false;
    }

    //Leading base
    if (ix + 2 < str.size() && str[ix] == L'0') {
      switch (str[ix+1]) {
      case L'b':
      case L'B':
        base = 2;
        ix += 2;
        break;

      case L'o':
      case L'O':
        base = 8;
        ix += 2;
        break;

      case L'x':
      case L'X':
        base = 16;
        ix += 2;
        break;
      }
    }

    //Digits
    do {
      unsigned value;
      wchar_t curr = str[ix++];

      if (curr >= L'0' && curr <= L'9')
        value = curr - L'0';
      else if (curr >= L'a' && curr <= L'f')
        value = 10 + curr - L'a';
      else if (curr >= L'A' && curr <= L'F')
        value = 10 + curr - L'A';
      else
        break;

      if (value >= base)
        break;

      dst *= base;
      dst += value;
    } while (ix < str.size());

    //Trailing whitespace
    while (ix < str.size() && iswspace(str[ix]))
      ++ix;

    //Sign
    if (negative)
      dst = -dst;

    //If !end, we don't allow trailing garbage; otherwise, we do
    if (end) *end = ix;
    return ix == str.size() || end;
  }

  bool parseBool(const wstring& str) {
    signed asNumber;
    if (parseInteger(asNumber, str))
      return asNumber != 0;
    else
      return str.size() > 0;
  }
}
<commit_msg>Numeric parsing now stops point where expected.<commit_after>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string>
#include <cctype>
#include <iostream>

#include "common.hxx"

using namespace std;

namespace tglng {
  bool parseInteger(signed& dst, const wstring& str,
                    unsigned offset, unsigned* end) {
    unsigned ix = offset;
    bool negative = false;
    unsigned base = 10;

    dst = 0;

    //Skip leading whitespace
    while (ix < str.size() && iswspace(str[ix]))
      ++ix;

    //If hit EOI, reject
    if (ix >= str.size()) {
      if (end) *end = ix;
      return false;
    }

    //Leading sign
    if (str[ix] == L'+') ++ix;
    else if (str[ix] == L'-') {
      ++ix;
      negative = true;
    }

    if (ix >= str.size()) {
      if (end) *end = ix;
      return false;
    }

    //Leading base
    if (ix + 2 < str.size() && str[ix] == L'0') {
      switch (str[ix+1]) {
      case L'b':
      case L'B':
        base = 2;
        ix += 2;
        break;

      case L'o':
      case L'O':
        base = 8;
        ix += 2;
        break;

      case L'x':
      case L'X':
        base = 16;
        ix += 2;
        break;
      }
    }

    //Digits
    do {
      unsigned value;
      wchar_t curr = str[ix];

      if (curr >= L'0' && curr <= L'9')
        value = curr - L'0';
      else if (curr >= L'a' && curr <= L'f')
        value = 10 + curr - L'a';
      else if (curr >= L'A' && curr <= L'F')
        value = 10 + curr - L'A';
      else
        break;

      if (value >= base)
        break;

      dst *= base;
      dst += value;
      ++ix;
    } while (ix < str.size());

    //Trailing whitespace.
    //Don't skip if trailing garbage is allowed.
    while (ix < str.size() && iswspace(str[ix]) && !end)
      ++ix;

    //Sign
    if (negative)
      dst = -dst;

    //If !end, we don't allow trailing garbage; otherwise, we do
    if (end) *end = ix;
    return ix == str.size() || end;
  }

  bool parseBool(const wstring& str) {
    signed asNumber;
    if (parseInteger(asNumber, str))
      return asNumber != 0;
    else
      return str.size() > 0;
  }
}
<|endoftext|>


<commit_before>#include "FLMTORCH.H"

#include "EFFECT2.H"
#include "CONTROL.H"
#include "DRAW.H"
#include "LARA.H"
#include "LARAFLAR.H"
#include "OBJECTS.H"
#if PC_VERSION
#include "GAME.H"
#else
#include "SETUP.H"
#endif
#include "SPECIFIC.H"
#include "TOMB4FX.H"

#if PSX_VERSION || PSXPC_VERSION
#include "MISC.H"
#endif

static short FireBounds[12] =
{
	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF8E4, 0x071C, 0xEAAC, 0x1554, 0xF8E4, 0x071C
};

short torchroom = 255;

void FlameTorchControl(short item_number)//3A8F4, 3ADF4
{
	UNIMPLEMENTED();
}

void GetFlameTorch()//3A830, 3AD30(<) (F)
{
	if (lara.gun_type == 7)
	{
		CreateFlare(FLARE_ITEM, 0);
	}

	//loc_3A864
	lara.gun_status = 4;
	lara.request_gun_type = 8;
	lara.gun_type = 8;
	lara.left_arm.lock = 0;
	lara.left_arm.frame_number = 0;
	lara.left_arm.anim_number = objects[TORCH_ANIM].anim_index;
	lara.flare_control_left = 1;
	lara.left_arm.frame_base = anims[objects[TORCH_ANIM].anim_index].frame_ptr;
	lara.target->touch_bits = ((unsigned long*)meshes[objects[TORCH_ANIM].mesh_index])[26];
}

void DoFlameTorch()//3A3CC, 3A8CC
{
	UNIMPLEMENTED();
}

void FireCollision(short item_num, struct ITEM_INFO* l, struct COLL_INFO* coll)//3A068, 3A568
{
	UNIMPLEMENTED();
}

void TriggerTorchFlame(short item_number, long Node)//39E88, 3A388 (F)
{
	struct SPARKS* sptr = &spark[GetFreeSpark()];
	long size;

	sptr->On = 1;

	sptr->sR = 255;
	sptr->sG = (GetRandomControl() & 0x1F) + 48;
	sptr->sB = 48;

	sptr->dR = (GetRandomControl() & 0x3F) - 64;
	sptr->dG = (GetRandomControl() & 0x3F) + -128;
	sptr->dB = 32;

	sptr->FadeToBlack = 8;
	sptr->ColFadeSpeed = (GetRandomControl() & 3) + 12;

	sptr->TransType = 2;

	sptr->Life = sptr->sLife = (GetRandomControl() & 7) + 24;

	sptr->y = 0;
	sptr->x = (GetRandomControl() & 0xF) - 8;
	sptr->z = (GetRandomControl() & 0xF) - 8;

	sptr->Xvel = (GetRandomControl() & 0xFF) - 128;
	sptr->Yvel = -((GetRandomControl() & 0xF) + 16);
	sptr->Zvel = GetRandomControl() - 128;

	sptr->Friction = 5;
	sptr->Flags = 4762;

	sptr->RotAng = GetRandomControl() & 0xFFF;

	if (GetRandomControl() & 1)
		sptr->RotAdd = -((GetRandomControl() & 0xF) + 16);
	else
		sptr->RotAdd = (GetRandomControl() & 0xF) + 16;

	sptr->Gravity = -((GetRandomControl() & 0x1F) + 16);
	sptr->NodeNumber = Node;
	sptr->MaxYvel = -((GetRandomControl() & 7) + 16);
	sptr->FxObj = item_number;
	sptr->Scalar = 1;

	size = (GetRandomControl() & 0x1F) + 80;
	sptr->sSize = size;
	sptr->Size = size;
	sptr->dSize = size >> 3;
}<commit_msg>Saturn compile patch<commit_after>#include "FLMTORCH.H"

#include "EFFECT2.H"
#include "CONTROL.H"
#include "DRAW.H"
#include "LARA.H"
#include "LARAFLAR.H"
#include "OBJECTS.H"
#if PC_VERSION
#include "GAME.H"
#else
#include "SETUP.H"
#endif
#include "SPECIFIC.H"
#include "TOMB4FX.H"

#if PSX_VERSION || PSXPC_VERSION || SAT_VERSION
#include "MISC.H"
#endif

static short FireBounds[12] =
{
	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF8E4, 0x071C, 0xEAAC, 0x1554, 0xF8E4, 0x071C
};

short torchroom = 255;

void FlameTorchControl(short item_number)//3A8F4, 3ADF4
{
	UNIMPLEMENTED();
}

void GetFlameTorch()//3A830, 3AD30(<) (F)
{
	if (lara.gun_type == 7)
	{
		CreateFlare(FLARE_ITEM, 0);
	}

	//loc_3A864
	lara.gun_status = 4;
	lara.request_gun_type = 8;
	lara.gun_type = 8;
	lara.left_arm.lock = 0;
	lara.left_arm.frame_number = 0;
	lara.left_arm.anim_number = objects[TORCH_ANIM].anim_index;
	lara.flare_control_left = 1;
	lara.left_arm.frame_base = anims[objects[TORCH_ANIM].anim_index].frame_ptr;
	lara.target->touch_bits = ((unsigned long*)meshes[objects[TORCH_ANIM].mesh_index])[26];
}

void DoFlameTorch()//3A3CC, 3A8CC
{
	UNIMPLEMENTED();
}

void FireCollision(short item_num, struct ITEM_INFO* l, struct COLL_INFO* coll)//3A068, 3A568
{
	UNIMPLEMENTED();
}

void TriggerTorchFlame(short item_number, long Node)//39E88, 3A388 (F)
{
	struct SPARKS* sptr = &spark[GetFreeSpark()];
	long size;

	sptr->On = 1;

	sptr->sR = 255;
	sptr->sG = (GetRandomControl() & 0x1F) + 48;
	sptr->sB = 48;

	sptr->dR = (GetRandomControl() & 0x3F) - 64;
	sptr->dG = (GetRandomControl() & 0x3F) + -128;
	sptr->dB = 32;

	sptr->FadeToBlack = 8;
	sptr->ColFadeSpeed = (GetRandomControl() & 3) + 12;

	sptr->TransType = 2;

	sptr->Life = sptr->sLife = (GetRandomControl() & 7) + 24;

	sptr->y = 0;
	sptr->x = (GetRandomControl() & 0xF) - 8;
	sptr->z = (GetRandomControl() & 0xF) - 8;

	sptr->Xvel = (GetRandomControl() & 0xFF) - 128;
	sptr->Yvel = -((GetRandomControl() & 0xF) + 16);
	sptr->Zvel = GetRandomControl() - 128;

	sptr->Friction = 5;
	sptr->Flags = 4762;

	sptr->RotAng = GetRandomControl() & 0xFFF;

	if (GetRandomControl() & 1)
		sptr->RotAdd = -((GetRandomControl() & 0xF) + 16);
	else
		sptr->RotAdd = (GetRandomControl() & 0xF) + 16;

	sptr->Gravity = -((GetRandomControl() & 0x1F) + 16);
	sptr->NodeNumber = Node;
	sptr->MaxYvel = -((GetRandomControl() & 7) + 16);
	sptr->FxObj = item_number;
	sptr->Scalar = 1;

	size = (GetRandomControl() & 0x1F) + 80;
	sptr->sSize = size;
	sptr->Size = size;
	sptr->dSize = size >> 3;
}<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// 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.                                           //
// ======================================================================== //

// ospcommon
#include "ospcommon/tasking/parallel_for.h"
#include "ospcommon/utility/StringManip.h"
// sg
#include "../common/Data.h"
#include "Generator.h"
// vtk
#include <vtkImageData.h>
#include <vtkRTAnalyticSource.h>
#include <vtkSmartPointer.h>

namespace ospray {
  namespace sg {

    void generateVTKWaveletVolume(const std::shared_ptr<Node> &world,
                                  const std::vector<string_pair> &params)
    {
      auto volume_node = createNode("wavelet", "StructuredVolume");

      // get generator parameters

      vec3i dims(256, 256, 256);

      for (auto &p : params) {
        if (p.first == "dimensions") {
          auto string_dims = ospcommon::utility::split(p.second, 'x');
          if (string_dims.size() != 3) {
            std::cout << "WARNING: ignoring incorrect 'dimensions' parameter,"
                      << " it must be of the form 'dimensions=XxYxZ'"
                      << std::endl;
            continue;
          }

          dims = vec3i(std::atoi(string_dims[0].c_str()),
                       std::atoi(string_dims[1].c_str()),
                       std::atoi(string_dims[2].c_str()));
        } else {
          std::cout << "WARNING: unknown spheres generator parameter '"
                    << p.first << "' with value '" << p.second << "'"
                    << std::endl;
        }
      }

      // generate volume data

      std::cout << "...generating wavelet volume with dims=" << dims << "..."
                << std::endl;

      auto halfDims = dims / 2;

      vtkSmartPointer<vtkRTAnalyticSource> wavelet = vtkRTAnalyticSource::New();
      wavelet->SetWholeExtent(-halfDims.x, halfDims.x-1,
                              -halfDims.y, halfDims.y-1,
                              -halfDims.z, halfDims.z-1);

      wavelet->SetCenter(0, 0, 0);
      wavelet->SetMaximum(255);
      wavelet->SetStandardDeviation(.5);
      wavelet->SetXFreq(60);
      wavelet->SetYFreq(30);
      wavelet->SetZFreq(40);
      wavelet->SetXMag(10);
      wavelet->SetYMag(18);
      wavelet->SetZMag(5);
      wavelet->SetSubsampleRate(1);

      wavelet->Update();

      std::cout << "...data generated, now creating scene graph objects..."
                << std::endl;

      auto imageData = wavelet->GetOutput();

      // validate expected outputs

      std::string voxelType = imageData->GetScalarTypeAsString();

      if (voxelType != "float")
        throw std::runtime_error("wavelet not floats? got '" + voxelType + "'");

      auto dimentionality = imageData->GetDataDimension();

      if (dimentionality != 3)
        throw std::runtime_error("wavelet not 3 dimentional?");

      // import data into sg nodes

      dims = vec3i(imageData->GetDimensions()[0],
                   imageData->GetDimensions()[1],
                   imageData->GetDimensions()[2]);

      auto numVoxels = dims.product();

      auto *voxels_ptr = (float*)imageData->GetScalarPointer();

      auto voxel_data = std::make_shared<DataArray1f>(voxels_ptr, numVoxels);

      voxel_data->setName("voxelData");

      volume_node->add(voxel_data);

      // volume attributes

      volume_node->child("voxelType")  = voxelType;
      volume_node->child("dimensions") = dims;

      volume_node->createChild("stashed_vtk_source", "Node", wavelet);

      // add volume to world

      world->add(volume_node);

      std::cout << "...finished!" << std::endl;
    }

    OSPSG_REGISTER_GENERATE_FUNCTION(generateVTKWaveletVolume, vtkWavelet);

  }  // ::ospray::sg
}  // ::ospray
<commit_msg>allow "dims" as alias for "dimensions" as param to wavelet generator<commit_after>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// 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.                                           //
// ======================================================================== //

// ospcommon
#include "ospcommon/tasking/parallel_for.h"
#include "ospcommon/utility/StringManip.h"
// sg
#include "../common/Data.h"
#include "Generator.h"
// vtk
#include <vtkImageData.h>
#include <vtkRTAnalyticSource.h>
#include <vtkSmartPointer.h>

namespace ospray {
  namespace sg {

    void generateVTKWaveletVolume(const std::shared_ptr<Node> &world,
                                  const std::vector<string_pair> &params)
    {
      auto volume_node = createNode("wavelet", "StructuredVolume");

      // get generator parameters

      vec3i dims(256, 256, 256);

      for (auto &p : params) {
        if (p.first == "dimensions" || p.first == "dims") {
          auto string_dims = ospcommon::utility::split(p.second, 'x');
          if (string_dims.size() != 3) {
            std::cout << "WARNING: ignoring incorrect 'dimensions' parameter,"
                      << " it must be of the form 'dimensions=XxYxZ'"
                      << std::endl;
            continue;
          }

          dims = vec3i(std::atoi(string_dims[0].c_str()),
                       std::atoi(string_dims[1].c_str()),
                       std::atoi(string_dims[2].c_str()));
        } else {
          std::cout << "WARNING: unknown spheres generator parameter '"
                    << p.first << "' with value '" << p.second << "'"
                    << std::endl;
        }
      }

      // generate volume data

      std::cout << "...generating wavelet volume with dims=" << dims << "..."
                << std::endl;

      auto halfDims = dims / 2;

      vtkSmartPointer<vtkRTAnalyticSource> wavelet = vtkRTAnalyticSource::New();
      wavelet->SetWholeExtent(-halfDims.x, halfDims.x-1,
                              -halfDims.y, halfDims.y-1,
                              -halfDims.z, halfDims.z-1);

      wavelet->SetCenter(0, 0, 0);
      wavelet->SetMaximum(255);
      wavelet->SetStandardDeviation(.5);
      wavelet->SetXFreq(60);
      wavelet->SetYFreq(30);
      wavelet->SetZFreq(40);
      wavelet->SetXMag(10);
      wavelet->SetYMag(18);
      wavelet->SetZMag(5);
      wavelet->SetSubsampleRate(1);

      wavelet->Update();

      std::cout << "...data generated, now creating scene graph objects..."
                << std::endl;

      auto imageData = wavelet->GetOutput();

      // validate expected outputs

      std::string voxelType = imageData->GetScalarTypeAsString();

      if (voxelType != "float")
        throw std::runtime_error("wavelet not floats? got '" + voxelType + "'");

      auto dimentionality = imageData->GetDataDimension();

      if (dimentionality != 3)
        throw std::runtime_error("wavelet not 3 dimentional?");

      // import data into sg nodes

      dims = vec3i(imageData->GetDimensions()[0],
                   imageData->GetDimensions()[1],
                   imageData->GetDimensions()[2]);

      auto numVoxels = dims.product();

      auto *voxels_ptr = (float*)imageData->GetScalarPointer();

      auto voxel_data = std::make_shared<DataArray1f>(voxels_ptr, numVoxels);

      voxel_data->setName("voxelData");

      volume_node->add(voxel_data);

      // volume attributes

      volume_node->child("voxelType")  = voxelType;
      volume_node->child("dimensions") = dims;

      volume_node->createChild("stashed_vtk_source", "Node", wavelet);

      // add volume to world

      world->add(volume_node);

      std::cout << "...finished!" << std::endl;
    }

    OSPSG_REGISTER_GENERATE_FUNCTION(generateVTKWaveletVolume, vtkWavelet);

  }  // ::ospray::sg
}  // ::ospray
<|endoftext|>


<commit_before>/*******************************************************************************
 * Extend abstract domains with very specialized operations.
 *
 * FIXME: if we use the generic abtract domain (based on the
 * type-erasure idiom) we cannot extend abstract domains using traits
 * because we cannot access to the underlying domains.
 ******************************************************************************/

#pragma once
#include <crab/domains/generic_abstract_domain.hpp>
#include <crab/domains/abstract_domain_operators.hpp>

namespace crab {
namespace domains {

template <typename Domain> class checker_domain_traits;

// Perform constraint simplifications depending on the abstract domain
template <typename Domain> class constraint_simp_domain_traits {
public:
  using number_t = typename Domain::number_t;
  using variable_t = typename Domain::variable_t;
  using linear_expression_t = typename Domain::linear_expression_t;
  using linear_constraint_t = typename Domain::linear_constraint_t;
  using linear_constraint_system_t = typename Domain::linear_constraint_system_t;

  // Convert an equality into two inequalities. This is not
  // possible for machine arithmetic domains.
  static void lower_equality(const linear_constraint_t &cst,
                             linear_constraint_system_t &out_csts) {
    if (cst.is_equality()) {
      out_csts += linear_constraint_t(cst.expression(),
				      linear_constraint_t::INEQUALITY);
      out_csts += linear_constraint_t(cst.expression() * number_t(-1),
				      linear_constraint_t::INEQUALITY);
    } else {
      out_csts += cst;
    }
  }

  // Convert a disequality into a strict inequality:
  // - if cst is x!=y and abs_val |= x <= y then add x < y
  // - if cst is x!=y and abs_val |= x >= y then add x > y
  static void lower_disequality(const Domain &abs_val,
				const linear_constraint_t &cst,
				linear_constraint_system_t &out_csts) {

    // TODO: we could use abs_val to infer more disequalities from cst.
    auto get_binary_operands = [](const linear_constraint_t &c) ->
      boost::optional<std::pair<variable_t, variable_t>> {
	if (c.is_disequation()) {
	  if (c.size() == 2 && c.constant() == 0) {
	    auto it = c.begin();
	    auto nx = it->first;
	    auto vx = it->second;
	    ++it;
	    assert(it != c.end());
	    auto ny = it->first;
	    auto vy = it->second;
	    if (nx == (ny * -1)) {
	      return std::make_pair(vx, vy);
	    }
	  }
	}
      return boost::none;
    };

    if (auto pair = get_binary_operands(cst)) {
      variable_t x = (*pair).first;
      variable_t y = (*pair).second;
      linear_constraint_t x_le_y(x <= y);
      linear_constraint_t x_lt_y(linear_expression_t(x) < linear_expression_t(y));
      if (checker_domain_traits<Domain>::entail(abs_val, x_le_y)) {
	out_csts += x_lt_y;
      } else {
	linear_constraint_t x_ge_y(x >= y);
	linear_constraint_t x_gt_y(linear_expression_t(x) > linear_expression_t(y));
	if (checker_domain_traits<Domain>::entail(abs_val, x_ge_y)) {
	  out_csts += x_gt_y;
	}
      }
    }
  }
};

// Special operations needed by the checker
template <typename Domain> class checker_domain_traits {
public:
  using varname_t = typename Domain::varname_t;
  using number_t = typename Domain::number_t;
  using linear_constraint_t = typename Domain::linear_constraint_t;
  typedef
      typename Domain::linear_constraint_system_t linear_constraint_system_t;
  using disjunctive_linear_constraint_system_t =
      typename Domain::disjunctive_linear_constraint_system_t;

private:
  struct entailment {
    const Domain &m_dom;
    entailment(const Domain &dom) : m_dom(dom) {}
    bool operator()(const linear_constraint_t &cst) {
      Domain dom(m_dom); // copy is necessary
      linear_constraint_t neg_cst = cst.negate();
      dom += neg_cst;
      return dom.is_bottom();
    }
  };

  // Return true if (c1 or c2 or ... cn) entails (d1 and d2 and .. dn)
  static bool __entail(const disjunctive_linear_constraint_system_t &lhs,
                       const linear_constraint_system_t &rhs) {
    // -- trivial cases first
    if (rhs.is_false()) {
      return false;
    } else if (rhs.is_true()) {
      return true;
    } else if (lhs.is_false()) {
      return true;
    } else if (lhs.is_true()) {
      return false;
    }

    // -- return true if for all ci :: ci entails (d1 and d2 and .. dn)
    return std::all_of(
        lhs.begin(), lhs.end(), [&rhs](const linear_constraint_system_t &csts) {
          Domain lhs;
          lhs += csts;
          return std::all_of(
              rhs.begin(), rhs.end(),
              [&lhs](const linear_constraint_t &c) { return entail(lhs, c); });
        });
  }

public:
  /*
     Public API

     static bool entail(Domain&, const disjunctive_linear_constraint_system_t&);
     static bool entail(const disjunctive_linear_constraint_system_t&, Domain&);
     static bool entail(Domain&, const linear_constraint_t&);

     static bool intersect(Domain&, const linear_constraint_t&);
   */

  // Return true if lhs entails (c1 or c2 or ... cn)
  static bool entail(const Domain &lhs,
                     const disjunctive_linear_constraint_system_t &rhs) {
    // -- trivial cases first
    if (rhs.is_false()) {
      return false;
    } else if (rhs.is_true()) {
      return true;
    } else if (lhs.is_bottom()) {
      return true;
    } else if (lhs.is_top()) {
      return false;
    }
    // -- return true if exists ci such that lhs entails ci
    for (linear_constraint_system_t csts : rhs) {
      if (std::all_of(csts.begin(), csts.end(),
                      [&lhs](const linear_constraint_t &c) {
                        return entail(lhs, c);
                      })) {
        return true;
      }
    }
    return false;
  }

  // Return true if (c1 or c2 or ... cn) entails rhs
  static bool entail(const disjunctive_linear_constraint_system_t &lhs,
                     const Domain &rhs) {
    auto csts = rhs.to_linear_constraint_system();
    return __entail(lhs, csts);
  }

  // Return true if lhs entails rhs.
  static bool entail(const Domain &lhs, const linear_constraint_t &rhs) {
    if (lhs.is_bottom())
      return true;
    if (rhs.is_tautology())
      return true;
    if (rhs.is_contradiction())
      return false;

    CRAB_LOG("checker-entailment", linear_constraint_t tmp(rhs);
             crab::outs() << "Checking whether\n"
                          << lhs << "\nentails " << tmp << "\n";);

    bool res;
    entailment op(lhs);
    if (rhs.is_equality()) {
      // try to convert the equality into inequalities so when it's
      // negated we do not have disequalities.
      linear_constraint_system_t inequalities;
      constraint_simp_domain_traits<Domain>::lower_equality(rhs, inequalities);
      res = std::all_of(inequalities.begin(), inequalities.end(), op);
    } else {
      res = op(rhs);
    }

    CRAB_LOG("checker-entailment",
             if (res) { crab::outs() << "\t**entailment holds.\n"; } else {
               crab::outs() << "\t**entailment does not hold.\n";
             });

    // Note: we cannot convert rhs into Domain and then use the <=
    //       operator. The problem is that we cannot know for sure
    //       whether Domain can represent precisely rhs. It is not
    //       enough to do something like
    //
    //       Dom dom = rhs;
    //       if (dom.is_top()) { ... }

    return res;
  }

  // Return true if inv intersects with cst.
  static bool intersect(const Domain &inv, const linear_constraint_t &cst) {
    if (inv.is_bottom() || cst.is_contradiction())
      return false;
    if (inv.is_top() || cst.is_tautology())
      return true;

    Domain dom(inv);
    dom += cst;
    return !dom.is_bottom();
  }
};

// Special operations for applying reduction between domains.
template <typename Domain> class reduced_domain_traits {
public:
  using variable_t = typename Domain::variable_t;
  using linear_constraint_t = typename Domain::linear_constraint_t;
  typedef
      typename Domain::linear_constraint_system_t linear_constraint_system_t;

  static_assert(
      !std::is_same<Domain, abstract_domain<typename Domain::variable_t>>::value,
      "reduced_domain_traits not supported for generic domain");
  static_assert(
      !std::is_same<Domain,
                   abstract_domain_ref<typename Domain::variable_t>>::value,
      "reduced_domain_traits not supported for generic domain");

  // extract linear constraints from dom involving x and store in ctsts
  static void extract(Domain &dom, const variable_t &x,
                      linear_constraint_system_t &csts, bool only_equalities) {
    auto all_csts = dom.to_linear_constraint_system();
    for (auto const &cst : all_csts) {
      if (only_equalities && (!cst.is_equality())) {
        continue;
      }
      if (std::find(std::begin(cst.variables()), std::end(cst.variables()), x) !=
          std::end(cst.variables())) {
        csts += cst;
      }
    }
  }
};

// Default implementation of integer cast instructions:
// signed-extension, zero-extension and truncation.
//
// This implementation assumes that the abstract domain Domain models
// integers as mathematical integers and hence, bit-widths are mostly
// ignored. Moreover, it assumes that Domain does not model Booleans.
template<typename Domain> class int_cast_domain_traits {
public:
  using number_t = typename Domain::number_t;
  using variable_t = typename Domain::variable_t;

  static void apply(Domain &dom, int_conv_operation_t op,
		    const variable_t &dst, const variable_t &src) {
    if (!(dst.get_type().is_bool() || src.get_type().is_bool())) {
      dom.assign(dst, src);
    }

    /// Refine dst based on src's type
    if (op == crab::domains::OP_ZEXT) {
      if (src.get_type().is_bool()) {
	dom += (dst >= 0);
	dom += (dst <= 1);
      } else if (src.get_type().is_integer()) {
	unsigned bitwidth = src.get_type().get_integer_bitwidth();
	unsigned upper_bound = (1 << bitwidth) - 1;
	dom += (dst <= number_t(upper_bound));
      }
    }
  }
};

// DEPRECATED: the boxes domain has global state that should be reset
// by the client if multiple crab instances will be run. This is just
// a temporary hack. The proper solution is to avoid global state.
template<typename Domain> class special_domain_traits {
public:
  static void clear_global_state(void) {}
};

} // end namespace domains
} // end namespace crab
<commit_msg>fix: fix to commit 2a3190c7984dda2709a9179e52bf0b52970c3d52<commit_after>/*******************************************************************************
 * Extend abstract domains with very specialized operations.
 *
 * FIXME: if we use the generic abtract domain (based on the
 * type-erasure idiom) we cannot extend abstract domains using traits
 * because we cannot access to the underlying domains.
 ******************************************************************************/

#pragma once
#include <crab/domains/generic_abstract_domain.hpp>
#include <crab/domains/abstract_domain_operators.hpp>

namespace crab {
namespace domains {

template <typename Domain> class checker_domain_traits;

// Perform constraint simplifications depending on the abstract domain
template <typename Domain> class constraint_simp_domain_traits {
public:
  using number_t = typename Domain::number_t;
  using variable_t = typename Domain::variable_t;
  using linear_expression_t = typename Domain::linear_expression_t;
  using linear_constraint_t = typename Domain::linear_constraint_t;
  using linear_constraint_system_t = typename Domain::linear_constraint_system_t;

  // Convert an equality into two inequalities. This is not
  // possible for machine arithmetic domains.
  static void lower_equality(const linear_constraint_t &cst,
                             linear_constraint_system_t &out_csts) {
    if (cst.is_equality()) {
      out_csts += linear_constraint_t(cst.expression(),
				      linear_constraint_t::INEQUALITY);
      out_csts += linear_constraint_t(cst.expression() * number_t(-1),
				      linear_constraint_t::INEQUALITY);
    } else {
      out_csts += cst;
    }
  }

  // Convert a disequality into a strict inequality:
  // - if cst is x!=y and abs_val |= x <= y then add x < y
  // - if cst is x!=y and abs_val |= x >= y then add x > y
  static void lower_disequality(const Domain &abs_val,
				const linear_constraint_t &cst,
				linear_constraint_system_t &out_csts) {

    // TODO: we could use abs_val to infer more disequalities from cst.
    auto get_binary_operands = [](const linear_constraint_t &c) ->
      boost::optional<std::pair<variable_t, variable_t>> {
	if (c.is_disequation()) {
	  if (c.size() == 2 && c.constant() == 0) {
	    auto it = c.begin();
	    auto nx = it->first;
	    auto vx = it->second;
	    ++it;
	    assert(it != c.end());
	    auto ny = it->first;
	    auto vy = it->second;
	    if (nx == (ny * -1)) {
	      return std::make_pair(vx, vy);
	    }
	  }
	}
      return boost::none;
    };

    if (auto pair = get_binary_operands(cst)) {
      variable_t x = (*pair).first;
      variable_t y = (*pair).second;
      linear_constraint_t x_le_y(x <= y);
      linear_constraint_t x_lt_y(linear_expression_t(x) < linear_expression_t(y));
      if (checker_domain_traits<Domain>::entail(abs_val, x_le_y)) {
	out_csts += x_lt_y;
      } else {
	linear_constraint_t x_ge_y(x >= y);
	linear_constraint_t x_gt_y(linear_expression_t(x) > linear_expression_t(y));
	if (checker_domain_traits<Domain>::entail(abs_val, x_ge_y)) {
	  out_csts += x_gt_y;
	}
      }
    }
  }
};

// Special operations needed by the checker
template <typename Domain> class checker_domain_traits {
public:
  using varname_t = typename Domain::varname_t;
  using number_t = typename Domain::number_t;
  using linear_constraint_t = typename Domain::linear_constraint_t;
  typedef
      typename Domain::linear_constraint_system_t linear_constraint_system_t;
  using disjunctive_linear_constraint_system_t =
      typename Domain::disjunctive_linear_constraint_system_t;

private:
  struct entailment {
    const Domain &m_dom;
    entailment(const Domain &dom) : m_dom(dom) {}
    bool operator()(const linear_constraint_t &cst) {
      Domain dom(m_dom); // copy is necessary
      linear_constraint_t neg_cst = cst.negate();
      dom += neg_cst;
      return dom.is_bottom();
    }
  };

  // Return true if (c1 or c2 or ... cn) entails (d1 and d2 and .. dn)
  static bool __entail(const disjunctive_linear_constraint_system_t &lhs,
                       const linear_constraint_system_t &rhs) {
    // -- trivial cases first
    if (rhs.is_false()) {
      return false;
    } else if (rhs.is_true()) {
      return true;
    } else if (lhs.is_false()) {
      return true;
    } else if (lhs.is_true()) {
      return false;
    }

    // -- return true if for all ci :: ci entails (d1 and d2 and .. dn)
    return std::all_of(
        lhs.begin(), lhs.end(), [&rhs](const linear_constraint_system_t &csts) {
          Domain lhs;
          lhs += csts;
          return std::all_of(
              rhs.begin(), rhs.end(),
              [&lhs](const linear_constraint_t &c) { return entail(lhs, c); });
        });
  }

public:
  /*
     Public API

     static bool entail(Domain&, const disjunctive_linear_constraint_system_t&);
     static bool entail(const disjunctive_linear_constraint_system_t&, Domain&);
     static bool entail(Domain&, const linear_constraint_t&);

     static bool intersect(Domain&, const linear_constraint_t&);
   */

  // Return true if lhs entails (c1 or c2 or ... cn)
  static bool entail(const Domain &lhs,
                     const disjunctive_linear_constraint_system_t &rhs) {
    // -- trivial cases first
    if (rhs.is_false()) {
      return false;
    } else if (rhs.is_true()) {
      return true;
    } else if (lhs.is_bottom()) {
      return true;
    } else if (lhs.is_top()) {
      return false;
    }
    // -- return true if exists ci such that lhs entails ci
    for (linear_constraint_system_t csts : rhs) {
      if (std::all_of(csts.begin(), csts.end(),
                      [&lhs](const linear_constraint_t &c) {
                        return entail(lhs, c);
                      })) {
        return true;
      }
    }
    return false;
  }

  // Return true if (c1 or c2 or ... cn) entails rhs
  static bool entail(const disjunctive_linear_constraint_system_t &lhs,
                     const Domain &rhs) {
    auto csts = rhs.to_linear_constraint_system();
    return __entail(lhs, csts);
  }

  // Return true if lhs entails rhs.
  static bool entail(const Domain &lhs, const linear_constraint_t &rhs) {
    if (lhs.is_bottom())
      return true;
    if (rhs.is_tautology())
      return true;
    if (rhs.is_contradiction())
      return false;

    CRAB_LOG("checker-entailment", linear_constraint_t tmp(rhs);
             crab::outs() << "Checking whether\n"
                          << lhs << "\nentails " << tmp << "\n";);

    bool res;
    entailment op(lhs);
    if (rhs.is_equality()) {
      // try to convert the equality into inequalities so when it's
      // negated we do not have disequalities.
      linear_constraint_system_t inequalities;
      constraint_simp_domain_traits<Domain>::lower_equality(rhs, inequalities);
      res = std::all_of(inequalities.begin(), inequalities.end(), op);
    } else {
      res = op(rhs);
    }

    CRAB_LOG("checker-entailment",
             if (res) { crab::outs() << "\t**entailment holds.\n"; } else {
               crab::outs() << "\t**entailment does not hold.\n";
             });

    // Note: we cannot convert rhs into Domain and then use the <=
    //       operator. The problem is that we cannot know for sure
    //       whether Domain can represent precisely rhs. It is not
    //       enough to do something like
    //
    //       Dom dom = rhs;
    //       if (dom.is_top()) { ... }

    return res;
  }

  // Return true if inv intersects with cst.
  static bool intersect(const Domain &inv, const linear_constraint_t &cst) {
    if (inv.is_bottom() || cst.is_contradiction())
      return false;
    if (inv.is_top() || cst.is_tautology())
      return true;

    Domain dom(inv);
    dom += cst;
    return !dom.is_bottom();
  }
};

// Special operations for applying reduction between domains.
template <typename Domain> class reduced_domain_traits {
public:
  using variable_t = typename Domain::variable_t;
  using linear_constraint_t = typename Domain::linear_constraint_t;
  typedef
      typename Domain::linear_constraint_system_t linear_constraint_system_t;

  static_assert(
      !std::is_same<Domain, abstract_domain<typename Domain::variable_t>>::value,
      "reduced_domain_traits not supported for generic domain");
  static_assert(
      !std::is_same<Domain,
                   abstract_domain_ref<typename Domain::variable_t>>::value,
      "reduced_domain_traits not supported for generic domain");

  // extract linear constraints from dom involving x and store in ctsts
  static void extract(Domain &dom, const variable_t &x,
                      linear_constraint_system_t &csts, bool only_equalities) {
    auto all_csts = dom.to_linear_constraint_system();
    for (auto const &cst : all_csts) {
      if (only_equalities && (!cst.is_equality())) {
        continue;
      }
      if (std::find(std::begin(cst.variables()), std::end(cst.variables()), x) !=
          std::end(cst.variables())) {
        csts += cst;
      }
    }
  }
};

// Default implementation of integer cast instructions:
// signed-extension, zero-extension and truncation.
//
// This implementation assumes that the abstract domain Domain models
// integers as mathematical integers and hence, bit-widths are mostly
// ignored. Moreover, it assumes that Domain does not model Booleans.
template<typename Domain> class int_cast_domain_traits {
public:
  using number_t = typename Domain::number_t;
  using variable_t = typename Domain::variable_t;

  static void apply(Domain &dom, int_conv_operation_t op,
		    const variable_t &dst, const variable_t &src) {

    if (!(dst.get_type().is_bool() || src.get_type().is_bool())) {
      dom.assign(dst, src);
    } else {
      dom -= dst;
    }

    /// Refine dst based on src's type
    if (op == crab::domains::OP_ZEXT) {
      if (src.get_type().is_bool()) {
	dom += (dst >= 0);
	dom += (dst <= 1);
      } else if (src.get_type().is_integer()) {
	unsigned bitwidth = src.get_type().get_integer_bitwidth();
	number_t upper_bound = (number_t(1) << number_t(bitwidth)) - number_t(1);
	dom += (dst <= number_t(upper_bound));
      }
    }
  }
};

// DEPRECATED: the boxes domain has global state that should be reset
// by the client if multiple crab instances will be run. This is just
// a temporary hack. The proper solution is to avoid global state.
template<typename Domain> class special_domain_traits {
public:
  static void clear_global_state(void) {}
};

} // end namespace domains
} // end namespace crab
<|endoftext|>