<commit_before>/*************************************************************************
 *
 * Copyright (c) 2011 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

namespace mdds {

template<typename _Key, typename _Data>
rectangle_set<_Key,_Data>::rectangle_set()
{
}

template<typename _Key, typename _Data>
rectangle_set<_Key,_Data>::rectangle_set(const rectangle_set& r) :
    m_inner_map(r.m_inner_map),
    m_dataset(r.m_dataset)
{
    build_outer_segment_tree();
}

template<typename _Key, typename _Data>
rectangle_set<_Key,_Data>::~rectangle_set()
{
}

template<typename _Key, typename _Data>
rectangle_set<_Key,_Data>& rectangle_set<_Key,_Data>::operator= (const rectangle_set& r)
{
    clear(); // Don't forget to clear the internal state beforehands.

    m_inner_map = r.m_inner_map;
    m_dataset = r.m_dataset;
    build_outer_segment_tree();
    return *this;
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::operator== (const rectangle_set& r) const
{
    if (m_dataset.size() != r.m_dataset.size())
        return false;

    typename dataset_type::const_iterator itr = m_dataset.begin(), itr_end = m_dataset.end();
    for (; itr != itr_end; ++itr)
    {
        typename dataset_type::const_iterator itr_rhs = r.m_dataset.find(itr->first);
        if (itr_rhs == r.m_dataset.end())
            return false;

        if (itr->second != itr_rhs->second)
            return false;
    }

    return true;
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::insert(key_type x1, key_type y1, key_type x2, key_type y2, data_type* data)
{
    if (x1 >= x2 || y1 >= y2)
        throw invalid_arg_error("specified range coordinates are invalid.");

    // Make sure this is not a duplicate.
    if (m_dataset.find(data) != m_dataset.end())
        return false;

    // Check if interval x1 - x2 is already stored.
    interval_type outer_interval = interval_type(x1, x2);
    typename inner_segment_map_type::iterator itr = m_inner_map.find(outer_interval);
    if (itr == m_inner_map.end())
    {
        // this interval has not yet been stored.  Create a new inner segment
        // tree instance for this interval.
        ::std::pair<typename inner_segment_map_type::iterator, bool> r =
            m_inner_map.insert(outer_interval, new inner_type);
        if (!r.second)
            throw general_error("inner segment tree insertion failed.");

        itr = r.first;

        // Register the pointer to this inner segment tree instance with the
        // outer segment tree.
        if (!m_outer_segments.insert(x1, x2, itr->second))
            // This should never fail if my logic is correct.
            throw general_error("failed to insert an inner segment tree pointer into the outer segment tree.");
    }

    inner_type* inner_tree = itr->second;
    inner_tree->insert(y1, y2, data);
    m_dataset.insert(typename dataset_type::value_type(data, rectangle(x1, y1, x2, y2)));

    return true;
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::search(key_type x, key_type y, search_result_type& result)
{
    typename outer_type::search_result_type inner_trees;
    if (!m_outer_segments.is_tree_valid())
        m_outer_segments.build_tree();

    if (!m_outer_segments.search(x, inner_trees))
        return false;

    typename outer_type::search_result_type::iterator itr_tree = inner_trees.begin(), itr_tree_end = inner_trees.end();
    for (; itr_tree != itr_tree_end; ++itr_tree)
    {
        inner_type* inner_tree = *itr_tree;
        if (!inner_tree->is_tree_valid())
            inner_tree->build_tree();

        // Search all relevant inner trees and aggregate results.
        if (!inner_tree->search(y, result))
            return false;
    }
    return true;
}

template<typename _Key, typename _Data>
typename rectangle_set<_Key,_Data>::search_result
rectangle_set<_Key,_Data>::search(key_type x, key_type y)
{
    search_result result;
    typename outer_type::search_result_type inner_trees;
    if (!m_outer_segments.is_tree_valid())
        m_outer_segments.build_tree();

    if (!m_outer_segments.search(x, inner_trees))
        return result;

    typename outer_type::search_result_type::iterator itr_tree = inner_trees.begin(), itr_tree_end = inner_trees.end();
    for (; itr_tree != itr_tree_end; ++itr_tree)
    {
        inner_type* inner_tree = *itr_tree;
        if (!inner_tree->is_tree_valid())
            inner_tree->build_tree();

        // Search all relevant inner trees and aggregate results.
        inner_tree->search(y, result);
    }
    return result;
}

template<typename _Key, typename _Data>
void rectangle_set<_Key,_Data>::remove(data_type* data)
{
    typename dataset_type::iterator itr_data = m_dataset.find(data);
    if (itr_data == m_dataset.end())
        // The data is not stored in this data structure.
        return;

    const rectangle& rect = itr_data->second;

    // Find the corresponding inner segment tree for this outer interval.
    interval_type outer(rect.x1, rect.x2);
    typename inner_segment_map_type::iterator itr_seg = m_inner_map.find(outer);
    if (itr_seg == m_inner_map.end())
        throw general_error("inconsistent internal state: failed to find an internal segment tree for an existing interval.");

    // Remove data from the inner segment tree.
    inner_type* inner_tree = itr_seg->second;
    inner_tree->remove(data);
    if (inner_tree->empty())
    {
        // This inner tree is now empty.  Erase it.
        m_outer_segments.remove(inner_tree);
        m_inner_map.erase(itr_seg);
    }

    // Remove it from the data set as well.
    m_dataset.erase(data);
}

template<typename _Key, typename _Data>
void rectangle_set<_Key,_Data>::clear()
{
    m_outer_segments.clear();
    m_inner_map.clear();
    m_dataset.clear();
}

template<typename _Key, typename _Data>
size_t rectangle_set<_Key,_Data>::size() const
{
    return m_dataset.size();
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::empty() const
{
    return m_dataset.empty();
}

template<typename _Key, typename _Data>
void rectangle_set<_Key,_Data>::build_outer_segment_tree()
{
    // Re-construct the outer segment tree from the authoritative inner tree
    // map.
    typename inner_segment_map_type::iterator itr = m_inner_map.begin(), itr_end = m_inner_map.end();
    for (; itr != itr_end; ++itr)
    {
        const interval_type& interval = itr->first;
        inner_type* tree = itr->second;
        m_outer_segments.insert(interval.first, interval.second, tree);
    }
}

#ifdef UNIT_TEST
template<typename _Key, typename _Data>
void rectangle_set<_Key,_Data>::dump_rectangles() const
{
    using namespace std;
    cout << "dump rectangles ------------------------------------------------" << endl;
    if (m_dataset.empty())
    {
        cout << "No rectangles in the data set." << endl;
        return;
    }

    typename dataset_type::const_iterator itr = m_dataset.begin(), itr_end = m_dataset.end();
    for (; itr != itr_end; ++itr)
    {
        const rectangle& rect = itr->second;
        cout << itr->first->name << ": (x1,y1,x2,y2) = "
            << "(" << rect.x1 << "," << rect.y1 << "," << rect.x2 << "," << rect.y2 << ")"
            << endl;
    }
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::verify_rectangles(const dataset_type& expected) const
{
    if (m_dataset.size() != expected.size())
        // Data sizes differ.
        return false;

    typename dataset_type::const_iterator itr_data = m_dataset.begin(), itr_data_end = m_dataset.end();
    for (; itr_data != itr_data_end; ++itr_data)
    {
        const data_type* data = itr_data->first;
        typename dataset_type::const_iterator itr_test = expected.find(data);
        if (itr_test == expected.end())
            // Pointer in one container but not in the other.
            return false;

        if (itr_data->second != itr_test->second)
            // Rectangle positions and/or sizes differ.
            return false;
    }

    return true;
}
#endif

}
<commit_msg>Improve the exception error message by including the passed values.<commit_after>/*************************************************************************
 *
 * Copyright (c) 2011-2012 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

#include <sstream>

namespace mdds {

template<typename _Key, typename _Data>
rectangle_set<_Key,_Data>::rectangle_set()
{
}

template<typename _Key, typename _Data>
rectangle_set<_Key,_Data>::rectangle_set(const rectangle_set& r) :
    m_inner_map(r.m_inner_map),
    m_dataset(r.m_dataset)
{
    build_outer_segment_tree();
}

template<typename _Key, typename _Data>
rectangle_set<_Key,_Data>::~rectangle_set()
{
}

template<typename _Key, typename _Data>
rectangle_set<_Key,_Data>& rectangle_set<_Key,_Data>::operator= (const rectangle_set& r)
{
    clear(); // Don't forget to clear the internal state beforehands.

    m_inner_map = r.m_inner_map;
    m_dataset = r.m_dataset;
    build_outer_segment_tree();
    return *this;
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::operator== (const rectangle_set& r) const
{
    if (m_dataset.size() != r.m_dataset.size())
        return false;

    typename dataset_type::const_iterator itr = m_dataset.begin(), itr_end = m_dataset.end();
    for (; itr != itr_end; ++itr)
    {
        typename dataset_type::const_iterator itr_rhs = r.m_dataset.find(itr->first);
        if (itr_rhs == r.m_dataset.end())
            return false;

        if (itr->second != itr_rhs->second)
            return false;
    }

    return true;
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::insert(key_type x1, key_type y1, key_type x2, key_type y2, data_type* data)
{
    if (x1 >= x2 || y1 >= y2)
    {
        std::ostringstream os;
        os << "specified range coordinates are invalid (x1=" << x1 << ",y1=" << y1 << ",x2=" << x2 << ",y2=" << y2 << ')';
        throw invalid_arg_error(os.str());
    }

    // Make sure this is not a duplicate.
    if (m_dataset.find(data) != m_dataset.end())
        return false;

    // Check if interval x1 - x2 is already stored.
    interval_type outer_interval = interval_type(x1, x2);
    typename inner_segment_map_type::iterator itr = m_inner_map.find(outer_interval);
    if (itr == m_inner_map.end())
    {
        // this interval has not yet been stored.  Create a new inner segment
        // tree instance for this interval.
        ::std::pair<typename inner_segment_map_type::iterator, bool> r =
            m_inner_map.insert(outer_interval, new inner_type);
        if (!r.second)
            throw general_error("inner segment tree insertion failed.");

        itr = r.first;

        // Register the pointer to this inner segment tree instance with the
        // outer segment tree.
        if (!m_outer_segments.insert(x1, x2, itr->second))
            // This should never fail if my logic is correct.
            throw general_error("failed to insert an inner segment tree pointer into the outer segment tree.");
    }

    inner_type* inner_tree = itr->second;
    inner_tree->insert(y1, y2, data);
    m_dataset.insert(typename dataset_type::value_type(data, rectangle(x1, y1, x2, y2)));

    return true;
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::search(key_type x, key_type y, search_result_type& result)
{
    typename outer_type::search_result_type inner_trees;
    if (!m_outer_segments.is_tree_valid())
        m_outer_segments.build_tree();

    if (!m_outer_segments.search(x, inner_trees))
        return false;

    typename outer_type::search_result_type::iterator itr_tree = inner_trees.begin(), itr_tree_end = inner_trees.end();
    for (; itr_tree != itr_tree_end; ++itr_tree)
    {
        inner_type* inner_tree = *itr_tree;
        if (!inner_tree->is_tree_valid())
            inner_tree->build_tree();

        // Search all relevant inner trees and aggregate results.
        if (!inner_tree->search(y, result))
            return false;
    }
    return true;
}

template<typename _Key, typename _Data>
typename rectangle_set<_Key,_Data>::search_result
rectangle_set<_Key,_Data>::search(key_type x, key_type y)
{
    search_result result;
    typename outer_type::search_result_type inner_trees;
    if (!m_outer_segments.is_tree_valid())
        m_outer_segments.build_tree();

    if (!m_outer_segments.search(x, inner_trees))
        return result;

    typename outer_type::search_result_type::iterator itr_tree = inner_trees.begin(), itr_tree_end = inner_trees.end();
    for (; itr_tree != itr_tree_end; ++itr_tree)
    {
        inner_type* inner_tree = *itr_tree;
        if (!inner_tree->is_tree_valid())
            inner_tree->build_tree();

        // Search all relevant inner trees and aggregate results.
        inner_tree->search(y, result);
    }
    return result;
}

template<typename _Key, typename _Data>
void rectangle_set<_Key,_Data>::remove(data_type* data)
{
    typename dataset_type::iterator itr_data = m_dataset.find(data);
    if (itr_data == m_dataset.end())
        // The data is not stored in this data structure.
        return;

    const rectangle& rect = itr_data->second;

    // Find the corresponding inner segment tree for this outer interval.
    interval_type outer(rect.x1, rect.x2);
    typename inner_segment_map_type::iterator itr_seg = m_inner_map.find(outer);
    if (itr_seg == m_inner_map.end())
        throw general_error("inconsistent internal state: failed to find an internal segment tree for an existing interval.");

    // Remove data from the inner segment tree.
    inner_type* inner_tree = itr_seg->second;
    inner_tree->remove(data);
    if (inner_tree->empty())
    {
        // This inner tree is now empty.  Erase it.
        m_outer_segments.remove(inner_tree);
        m_inner_map.erase(itr_seg);
    }

    // Remove it from the data set as well.
    m_dataset.erase(data);
}

template<typename _Key, typename _Data>
void rectangle_set<_Key,_Data>::clear()
{
    m_outer_segments.clear();
    m_inner_map.clear();
    m_dataset.clear();
}

template<typename _Key, typename _Data>
size_t rectangle_set<_Key,_Data>::size() const
{
    return m_dataset.size();
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::empty() const
{
    return m_dataset.empty();
}

template<typename _Key, typename _Data>
void rectangle_set<_Key,_Data>::build_outer_segment_tree()
{
    // Re-construct the outer segment tree from the authoritative inner tree
    // map.
    typename inner_segment_map_type::iterator itr = m_inner_map.begin(), itr_end = m_inner_map.end();
    for (; itr != itr_end; ++itr)
    {
        const interval_type& interval = itr->first;
        inner_type* tree = itr->second;
        m_outer_segments.insert(interval.first, interval.second, tree);
    }
}

#ifdef UNIT_TEST
template<typename _Key, typename _Data>
void rectangle_set<_Key,_Data>::dump_rectangles() const
{
    using namespace std;
    cout << "dump rectangles ------------------------------------------------" << endl;
    if (m_dataset.empty())
    {
        cout << "No rectangles in the data set." << endl;
        return;
    }

    typename dataset_type::const_iterator itr = m_dataset.begin(), itr_end = m_dataset.end();
    for (; itr != itr_end; ++itr)
    {
        const rectangle& rect = itr->second;
        cout << itr->first->name << ": (x1,y1,x2,y2) = "
            << "(" << rect.x1 << "," << rect.y1 << "," << rect.x2 << "," << rect.y2 << ")"
            << endl;
    }
}

template<typename _Key, typename _Data>
bool rectangle_set<_Key,_Data>::verify_rectangles(const dataset_type& expected) const
{
    if (m_dataset.size() != expected.size())
        // Data sizes differ.
        return false;

    typename dataset_type::const_iterator itr_data = m_dataset.begin(), itr_data_end = m_dataset.end();
    for (; itr_data != itr_data_end; ++itr_data)
    {
        const data_type* data = itr_data->first;
        typename dataset_type::const_iterator itr_test = expected.find(data);
        if (itr_test == expected.end())
            // Pointer in one container but not in the other.
            return false;

        if (itr_data->second != itr_test->second)
            // Rectangle positions and/or sizes differ.
            return false;
    }

    return true;
}
#endif

}
<|endoftext|>


<commit_before>#include "server_functions.h"
#include <string.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <netdb.h>
#include <stdlib.h>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"

#include "rpc.h"
#include "constants.h"
#include "helper_function.h"
#include "message_types.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *> * > proc_loc_dict;
//static map<rpcFunctionKey, list<service_info *> * > servicesDictionary;

static list<server_function_info *> roundRobinList;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/
void registration_request_handler(RegisterRequestMessage * message, int sock){
	const char * name = message->getName().c_str();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  //procedure_signature *  key = new procedure_signature(name, argTypes);
  procedure_signature key(name, argTypes);

  int status = 0;

  //if no key dosnt exist in map
	if (proc_loc_dict.find(key) == proc_loc_dict.end()) {
    //Adding to the map

    //int *memArgTypes = copyArgTypes(argTypes);
    //key = procedure_signature(name, memArgTypes);

    proc_loc_dict[key] = new list<server_info *>();
    server_info * entry = new server_info(server_identifier, port, sock);

    //Adding to roundRobinList
    server_function_info * info = new server_function_info(entry, key);
    roundRobinList.push_back(info);

  }else{

    bool sameLoc = false;
    list<server_info *> *hostList = proc_loc_dict[key];
    //list<server_info *> *hostList = proc_loc_dict.find(key);

    for (list<server_info *>::iterator it = hostList->begin(); it != hostList->end(); it++) {
      // IF THEY ARE AT THE SAME PLACE, THEY SHOULD HAVE TEH SAME SOCKET
      if((*it)->socket == sock){
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something
        sameLoc = true;
      }

    }
    //Same procedure signature, different location
  	if(!sameLoc){
       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList->push_back(new_msg_loc);
    }
  }

  RegisterSuccessMessage * success_message = new RegisterSuccessMessage(status);
  success_message->send(sock);
}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
int location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){

    //If the name are the same
    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){

      exist = true;

      LocSuccessMessage * success_message = new LocSuccessMessage((*it)->si->server_identifier, (*it)->si->port);

      success_message->send(sock);

      //When we have identified the correct procedure_signature use round robin and move that service to the end
      roundRobinList.splice(roundRobinList.end(), roundRobinList, it);

      break;
 		}
	}

  if(!exist){
    int reasoncode = 0;
    LocFailureMessage * failure_message = new LocFailureMessage(reasoncode);
    failure_message->send(sock);
  }

	return 0; //LOC_FAILURE
}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){ //'LOC_REQUEST'
    Message * cast1 = segment->getMessage();
    RegisterRequestMessage * rrm = dynamic_cast<RegisterRequestMessage*>(cast1);
    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){ //'REGISTER'
    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);
    retval = location_request_handler(lqm, sock);
  }

	return retval;
}

// Returns the binder address
string getBinderAddress() {
   char hostname[MAXHOSTNAMELEN + 1] = {'\0'};
   gethostname(hostname, sizeof(hostname));
   return string(hostname);
}

// Returns the binder port
int getBinderPort(int welcomeSocket) {
   struct sockaddr_in binderAddress;
   socklen_t binderAddressLength = sizeof(binderAddress);

   int result = getsockname(welcomeSocket, (struct sockaddr*) &binderAddress,
      &binderAddressLength);
   if (result < 0) {
      exit(-1);
   } // if

   return ntohs(binderAddress.sin_port);
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main(){

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  if (status != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    return 0;
  }

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, 5);

  cout << "BINDER_ADDRESS " << getBinderAddress() << endl;
  cout << "BINDER_PORT " << getBinderPort(sock) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);

    n = sock;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {

            Segment * segment = 0;
            status = Segment::receive(sock, segment);

            if (status < 0) {
                RegisterFailureMessage * failure_message = new RegisterFailureMessage(status);
                failure_message->send(sock);
                return status;
            }

            if (status == 0) {
              // client has closed the connection
              myToRemove.push_back(sock);
              return status;
            }

            request_handler(segment, sock);
          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<commit_msg>changes<commit_after>#include "server_functions.h"
#include <string.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <netdb.h>
#include <stdlib.h>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"

#include "rpc.h"
#include "constants.h"
#include "helper_function.h"
#include "message_types.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *> * > proc_loc_dict;
//static map<rpcFunctionKey, list<service_info *> * > servicesDictionary;

static list<server_info *> roundRobinList;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/
void registration_request_handler(RegisterRequestMessage * message, int sock){
	const char * name = message->getName().c_str();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  procedure_signature key(name, argTypes);

  int status = 0;

  //if no key dosnt exist in map
	if (proc_loc_dict.find(key) == proc_loc_dict.end()) {
    //Adding to the map

    //int *memArgTypes = copyArgTypes(argTypes);
    //key = procedure_signature(name, memArgTypes);

    proc_loc_dict[key] = new list<server_info *>();
    server_info * entry = new server_info(server_identifier, port, sock);

    //Adding to roundRobinList
    roundRobinList.push_back(entry);

  }else{

    bool sameLoc = false;
    list<server_info *> *hostList = proc_loc_dict[key];
    //list<server_info *> *hostList = proc_loc_dict.find(key);

    for (list<server_info *>::iterator it = hostList->begin(); it != hostList->end(); it++) {
      // IF THEY ARE AT THE SAME PLACE, THEY SHOULD HAVE TEH SAME SOCKET
      if((*it)->socket == sock){
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something
        sameLoc = true;
      }

    }
    //Same procedure signature, different location
  	if(!sameLoc){
       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList->push_back(new_msg_loc);
    }
  }

  RegisterSuccessMessage * success_message = new RegisterSuccessMessage(status);
  success_message->send(sock);
}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
int location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){

    //If the name are the same
    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){

      exist = true;

      LocSuccessMessage * success_message = new LocSuccessMessage((*it)->si->server_identifier, (*it)->si->port);

      success_message->send(sock);

      //When we have identified the correct procedure_signature use round robin and move that service to the end
      roundRobinList.splice(roundRobinList.end(), roundRobinList, it);

      break;
 		}
	}

  if(!exist){
    int reasoncode = 0;
    LocFailureMessage * failure_message = new LocFailureMessage(reasoncode);
    failure_message->send(sock);
  }

	return 0; //LOC_FAILURE
}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){ //'LOC_REQUEST'
    Message * cast1 = segment->getMessage();
    RegisterRequestMessage * rrm = dynamic_cast<RegisterRequestMessage*>(cast1);
    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){ //'REGISTER'
    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);
    retval = location_request_handler(lqm, sock);
  }

	return retval;
}

// Returns the binder address
string getBinderAddress() {
   char hostname[MAXHOSTNAMELEN + 1] = {'\0'};
   gethostname(hostname, sizeof(hostname));
   return string(hostname);
}

// Returns the binder port
int getBinderPort(int welcomeSocket) {
   struct sockaddr_in binderAddress;
   socklen_t binderAddressLength = sizeof(binderAddress);

   int result = getsockname(welcomeSocket, (struct sockaddr*) &binderAddress,
      &binderAddressLength);
   if (result < 0) {
      exit(-1);
   } // if

   return ntohs(binderAddress.sin_port);
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main(){

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  if (status != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    return 0;
  }

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, 5);

  cout << "BINDER_ADDRESS " << getBinderAddress() << endl;
  cout << "BINDER_PORT " << getBinderPort(sock) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);

    n = sock;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {

            Segment * segment = 0;
            status = Segment::receive(sock, segment);

            if (status < 0) {
                RegisterFailureMessage * failure_message = new RegisterFailureMessage(status);
                failure_message->send(sock);
                return status;
            }

            if (status == 0) {
              // client has closed the connection
              myToRemove.push_back(sock);
              return status;
            }

            request_handler(segment, sock);
          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#ifndef TYPE_SAFE_TAGGED_UNION_HPP_INCLUDED
#define TYPE_SAFE_TAGGED_UNION_HPP_INCLUDED

#include <new>

#include <type_safe/detail/aligned_union.hpp>
#include <type_safe/config.hpp>
#include <type_safe/strong_typedef.hpp>

namespace type_safe
{
    /// \exclude
    namespace detail
    {
        struct union_type_id : strong_typedef<union_type_id, std::size_t>,
                               strong_typedef_op::equality_comparison<union_type_id, bool>,
                               strong_typedef_op::relational_comparison<union_type_id, bool>
        {
            using strong_typedef<union_type_id, std::size_t>::strong_typedef;
        };

        //=== get_type_index ==//
        template <typename T, typename... Ts>
        struct get_type_index_impl;

        template <typename T, typename... Tail>
        struct get_type_index_impl<T, T, Tail...> : std::integral_constant<std::size_t, 0>
        {
        };

        template <typename T, typename Head, typename... Tail>
        struct get_type_index_impl<T, Head, Tail...>
            : std::integral_constant<std::size_t, 1 + get_type_index_impl<T, Tail...>::value>
        {
        };

        template <typename T, typename... Types>
        using get_type_index = get_type_index_impl<T, typename std::decay<Types>::type...>;
    } // namespace detail

    /// Tag type so no explicit template instantiation of function parameters is required.
    /// \module variant
    template <typename T>
    struct union_type
    {
    };

    /// Very basic typelist.
    /// \module variant
    template <typename... Ts>
    struct union_types
    {
    };

    /// A tagged union.
    ///
    /// It is much like a plain old C `union`,
    /// but remembers which type it currently stores.
    /// It can either store one of the given types or no type at all.
    /// \notes Like the C `union` it does not automatically destroy the currently stored type,
    /// and copy operations are deleted.
    /// \module variant
    template <typename... Types>
    class tagged_union
    {
    public:
        using types = union_types<typename std::decay<Types>::type...>;

        /// The id of a type.
        ///
        /// It is a [ts::strong_typedef]() for `std::size_t`
        /// and provides equality and relational comparison.
        class type_id : public strong_typedef<type_id, std::size_t>,
                        public strong_typedef_op::equality_comparison<type_id, bool>,
                        public strong_typedef_op::relational_comparison<type_id, bool>
        {
        public:
            /// \effects Initializes it to an invalid value.
            constexpr type_id() noexcept : strong_typedef<type_id, std::size_t>(sizeof...(Types))
            {
            }

            /// \effects Initializes it to the value of the type `T`.
            /// If `T` is not one of the types of the union types,
            /// it will be the same as the default constructor.
            template <typename T>
            constexpr type_id(union_type<T>) noexcept
            : type_id(detail::get_type_index<T, Types...>::value)
            {
            }

            /// \returns `true` if the id is valid,
            /// `false` otherwise.
            explicit operator bool() const noexcept
            {
                return *this != type_id();
            }

        private:
            explicit constexpr type_id(std::size_t value)
            : strong_typedef<type_id, std::size_t>(value)
            {
            }
        };

        /// A global invalid type id object.
        static constexpr type_id invalid_type = type_id();

        //=== constructors/destructors/assignment ===//
        tagged_union() noexcept = default;

        /// \notes Does not destroy the currently xtored type.
        ~tagged_union() noexcept = default;

        tagged_union(const tagged_union&) = delete;
        tagged_union& operator=(const tagged_union&) = delete;

        //=== modifiers ===//
        /// \effects Creates a new object of given type by perfectly forwarding `args`.
        /// \throws Anything thrown by `T`s constructor,
        /// in which case the union will stay empty.
        /// \requires The union must currently be empty.
        /// and `T` must be a valid type and constructible from the arguments.
        template <typename T, typename... Args>
        void emplace(union_type<T>, Args&&... args)
        {
            constexpr auto index = type_id(union_type<T>{});
            static_assert(index != invalid_type, "T must not be stored in variant");
            static_assert(std::is_constructible<T, Args&&...>::value,
                          "T not constructible from arguments");

            ::new (get_memory()) T(std::forward<Args>(args)...);
            cur_type_ = index;
        }

        /// \effects Destroys the currently stored type by calling its destructor,
        /// and setting the union to the empty state.
        /// \requires The union must currently store an object of the given type.
        template <typename T>
        void destroy(union_type<T> type) noexcept
        {
            check(type);
            value(type).~T();
            cur_type_ = invalid_type;
        }

        //=== accessors ===//
        /// \returns The [*type_id]() of the type currently stored,
        /// or [*invalid_type_id]() if there is none.
        const type_id& type() const noexcept
        {
            return cur_type_;
        }

        /// \returns `true` if there is a type stored,
        /// `false` otherwise.
        bool has_value() const noexcept
        {
            return type() != invalid_type;
        }

        /// \returns A (`const`) lvalue/rvalue reference to the currently stored type.
        /// \requires The union must currently store an object of the given type.
        /// \group value
        template <typename T>
        T& value(union_type<T> type) TYPE_SAFE_LVALUE_REF noexcept
        {
            check(type);
            return *static_cast<T*>(get_memory());
        }

        /// \group value
        template <typename T>
        const T& value(union_type<T> type) const TYPE_SAFE_LVALUE_REF noexcept
        {
            check(type);
            return *static_cast<const T*>(get_memory());
        }

#if TYPE_SAFE_USE_REF_QUALIFIERS
        /// \group value
        template <typename T>
            T&& value(union_type<T> type) && noexcept
        {
            check(type);
            return std::move(*static_cast<T*>(get_memory()));
        }

        /// \group value
        template <typename T>
        const T&& value(union_type<T> type) const && noexcept
        {
            check(type);
            return std::move(*static_cast<const T*>(get_memory()));
        }
#endif

    private:
        void* get_memory() noexcept
        {
            return static_cast<void*>(&storage_);
        }

        const void* get_memory() const noexcept
        {
            return static_cast<const void*>(&storage_);
        }

        template <typename T>
        void check(union_type<T> type) const noexcept
        {
            DEBUG_ASSERT(cur_type_ == type, detail::assert_handler{},
                         "different type stored in union");
        }

        using storage_t = detail::aligned_union_t<Types...>;
        storage_t storage_;
        type_id   cur_type_;
    };

    /// \exclude
    template <typename... Types>
    constexpr typename tagged_union<Types...>::type_id tagged_union<Types...>::invalid_type;

    /// \exclude
    namespace detail
    {
        template <class Union>
        class destroy_union;

        template <typename... Types>
        class destroy_union<tagged_union<Types...>>
        {
        public:
            static void destroy(tagged_union<Types...>& u) noexcept
            {
                auto idx = static_cast<std::size_t>(u.type());
                DEBUG_ASSERT(idx < sizeof...(Types), detail::assert_handler{});
                callbacks[idx](u);
            }

        private:
            template <typename T>
            static void destroy_impl(tagged_union<Types...>& u) noexcept
            {
                u.destroy(union_type<T>{});
            }

            using callback_type                        = void (*)(tagged_union<Types...>&);
            static constexpr callback_type callbacks[] = {&destroy_impl<Types>...};
        };
        template <typename... Types>
        constexpr typename destroy_union<tagged_union<Types...>>::callback_type
            destroy_union<tagged_union<Types...>>::callbacks[];

        template <class Union>
        class copy_union;

        template <typename... Types>
        class copy_union<tagged_union<Types...>>
        {
        public:
            static void copy(tagged_union<Types...>& dest, const tagged_union<Types...>& org)
            {
                DEBUG_ASSERT(!dest.has_value(), detail::assert_handler{});

                auto idx = static_cast<std::size_t>(org.type());
                DEBUG_ASSERT(idx < sizeof...(Types), detail::assert_handler{});
                callbacks[idx](dest, org);
            }

        private:
            template <typename T>
            static void copy_impl(tagged_union<Types...>& dest, const tagged_union<Types...>& org)
            {
                dest.emplace(union_type<T>{}, org.value(union_type<T>{}));
            }

            using callback_type = void (*)(tagged_union<Types...>&, const tagged_union<Types...>&);
            static constexpr callback_type callbacks[] = {&copy_impl<Types>...};
        };
        template <typename... Types>
        constexpr typename copy_union<tagged_union<Types...>>::callback_type
            copy_union<tagged_union<Types...>>::callbacks[];

        template <class Union>
        class move_union;

        template <typename... Types>
        class move_union<tagged_union<Types...>>
        {
        public:
            static void move(tagged_union<Types...>& dest, tagged_union<Types...>&& org)
            {
                DEBUG_ASSERT(!dest.has_value(), detail::assert_handler{});

                auto idx = static_cast<std::size_t>(org.type());
                DEBUG_ASSERT(idx < sizeof...(Types), detail::assert_handler{});
                callbacks[idx](dest, std::move(org));
            }

        private:
            template <typename T>
            static void move_impl(tagged_union<Types...>& dest, tagged_union<Types...>&& org)
            {
                dest.emplace(union_type<T>{}, std::move(org).value(union_type<T>{}));
            }

            using callback_type = void (*)(tagged_union<Types...>&, tagged_union<Types...>&&);
            static constexpr callback_type callbacks[] = {&move_impl<Types>...};
        };
        template <typename... Types>
        constexpr typename move_union<tagged_union<Types...>>::callback_type
            move_union<tagged_union<Types...>>::callbacks[];
    } // namespace detail

    /// \effects Destroys the type currently stored in the [ts::tagged_union](),
    /// by calling `u.destroy(union_type<T>{})`.
    /// \requires The union must currently store a type,
    /// i.e. `has_value()` must return `true`.
    /// \module variant
    template <typename... Types>
    void destroy(tagged_union<Types...>& u) noexcept
    {
        detail::destroy_union<tagged_union<Types...>>::destroy(u);
    }

    /// \effects Copies the type currently stored in one [ts::tagged_union]() to another.
    /// This is equivalent to calling `dest.emplace(union_type<T>{}, org.value(union_type<T>{}))` (1)/
    /// `dest.emplace(union_type<T>{}, std::move(org).value(union_type<T>{}))` (2),
    /// where `T` is the type currently stored in the union.
    /// \throws Anything by the copy/move constructor in which case nothing has changed.
    /// \requires `dest` must not store a type, but `org` must have one,
    /// and all types must be copyable/moveable.
    /// \group union_copy_move
    /// \module variant
    template <typename... Types>
    void copy(tagged_union<Types...>& dest, const tagged_union<Types...>& org)
    {
        detail::copy_union<tagged_union<Types...>>::copy(dest, org);
    }

    /// \group union_copy_move
    /// \module variant
    template <typename... Types>
    void move(tagged_union<Types...>& dest, tagged_union<Types...>&& org)
    {
        detail::move_union<tagged_union<Types...>>::move(dest, std::move(org));
    }
} // namespace type_safe

#endif // TYPE_SAFE_TAGGED_UNION_HPP_INCLUDED
<commit_msg>Change type_id to store index + 1<commit_after>// Copyright (C) 2016 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#ifndef TYPE_SAFE_TAGGED_UNION_HPP_INCLUDED
#define TYPE_SAFE_TAGGED_UNION_HPP_INCLUDED

#include <new>

#include <type_safe/detail/aligned_union.hpp>
#include <type_safe/config.hpp>
#include <type_safe/strong_typedef.hpp>

namespace type_safe
{
    /// \exclude
    namespace detail
    {
        struct union_type_id : strong_typedef<union_type_id, std::size_t>,
                               strong_typedef_op::equality_comparison<union_type_id, bool>,
                               strong_typedef_op::relational_comparison<union_type_id, bool>
        {
            using strong_typedef<union_type_id, std::size_t>::strong_typedef;
        };

        //=== get_type_index ==//
        template <typename T, typename... Ts>
        struct get_type_index_impl;

        template <typename T>
        struct get_type_index_impl<T> : std::integral_constant<std::size_t, 9>
        {
        };

        template <typename T, typename... Tail>
        struct get_type_index_impl<T, T, Tail...> : std::integral_constant<std::size_t, 1>
        {
        };

        template <typename T, typename Head, typename... Tail>
        struct get_type_index_impl<T, Head, Tail...>
            : std::integral_constant<std::size_t, 1 + get_type_index_impl<T, Tail...>::value>
        {
        };

        template <typename T, typename... Types>
        using get_type_index = get_type_index_impl<T, typename std::decay<Types>::type...>;
    } // namespace detail

    /// Tag type so no explicit template instantiation of function parameters is required.
    /// \module variant
    template <typename T>
    struct union_type
    {
    };

    /// Very basic typelist.
    /// \module variant
    template <typename... Ts>
    struct union_types
    {
    };

    /// A tagged union.
    ///
    /// It is much like a plain old C `union`,
    /// but remembers which type it currently stores.
    /// It can either store one of the given types or no type at all.
    /// \notes Like the C `union` it does not automatically destroy the currently stored type,
    /// and copy operations are deleted.
    /// \module variant
    template <typename... Types>
    class tagged_union
    {
    public:
        using types = union_types<typename std::decay<Types>::type...>;

        /// The id of a type.
        ///
        /// It is a [ts::strong_typedef]() for `std::size_t`
        /// and provides equality and relational comparison.
        class type_id : public strong_typedef<type_id, std::size_t>,
                        public strong_typedef_op::equality_comparison<type_id, bool>,
                        public strong_typedef_op::relational_comparison<type_id, bool>
        {
        public:
            /// \effects Initializes it to an invalid value.
            /// \notes The invalid value compares less than all valid values.
            constexpr type_id() noexcept : strong_typedef<type_id, std::size_t>(0u)
            {
            }

            /// \effects Initializes it to the value of the type `T`.
            /// If `T` is not one of the types of the union types,
            /// it will be the same as the default constructor.
            template <typename T>
            constexpr type_id(union_type<T>) noexcept
            : type_id(detail::get_type_index<T, Types...>::value)
            {
            }

            /// \returns `true` if the id is valid,
            /// `false` otherwise.
            explicit operator bool() const noexcept
            {
                return *this != type_id();
            }

        private:
            explicit constexpr type_id(std::size_t value)
            : strong_typedef<type_id, std::size_t>(value)
            {
            }
        };

        /// A global invalid type id object.
        static constexpr type_id invalid_type = type_id();

        //=== constructors/destructors/assignment ===//
        tagged_union() noexcept = default;

        /// \notes Does not destroy the currently xtored type.
        ~tagged_union() noexcept = default;

        tagged_union(const tagged_union&) = delete;
        tagged_union& operator=(const tagged_union&) = delete;

        //=== modifiers ===//
        /// \effects Creates a new object of given type by perfectly forwarding `args`.
        /// \throws Anything thrown by `T`s constructor,
        /// in which case the union will stay empty.
        /// \requires The union must currently be empty.
        /// and `T` must be a valid type and constructible from the arguments.
        template <typename T, typename... Args>
        void emplace(union_type<T>, Args&&... args)
        {
            constexpr auto index = type_id(union_type<T>{});
            static_assert(index != invalid_type, "T must not be stored in variant");
            static_assert(std::is_constructible<T, Args&&...>::value,
                          "T not constructible from arguments");

            ::new (get_memory()) T(std::forward<Args>(args)...);
            cur_type_ = index;
        }

        /// \effects Destroys the currently stored type by calling its destructor,
        /// and setting the union to the empty state.
        /// \requires The union must currently store an object of the given type.
        template <typename T>
        void destroy(union_type<T> type) noexcept
        {
            check(type);
            value(type).~T();
            cur_type_ = invalid_type;
        }

        //=== accessors ===//
        /// \returns The [*type_id]() of the type currently stored,
        /// or [*invalid_type_id]() if there is none.
        const type_id& type() const noexcept
        {
            return cur_type_;
        }

        /// \returns `true` if there is a type stored,
        /// `false` otherwise.
        bool has_value() const noexcept
        {
            return type() != invalid_type;
        }

        /// \returns A (`const`) lvalue/rvalue reference to the currently stored type.
        /// \requires The union must currently store an object of the given type.
        /// \group value
        template <typename T>
        T& value(union_type<T> type) TYPE_SAFE_LVALUE_REF noexcept
        {
            check(type);
            return *static_cast<T*>(get_memory());
        }

        /// \group value
        template <typename T>
        const T& value(union_type<T> type) const TYPE_SAFE_LVALUE_REF noexcept
        {
            check(type);
            return *static_cast<const T*>(get_memory());
        }

#if TYPE_SAFE_USE_REF_QUALIFIERS
        /// \group value
        template <typename T>
            T&& value(union_type<T> type) && noexcept
        {
            check(type);
            return std::move(*static_cast<T*>(get_memory()));
        }

        /// \group value
        template <typename T>
        const T&& value(union_type<T> type) const && noexcept
        {
            check(type);
            return std::move(*static_cast<const T*>(get_memory()));
        }
#endif

    private:
        void* get_memory() noexcept
        {
            return static_cast<void*>(&storage_);
        }

        const void* get_memory() const noexcept
        {
            return static_cast<const void*>(&storage_);
        }

        template <typename T>
        void check(union_type<T> type) const noexcept
        {
            DEBUG_ASSERT(cur_type_ == type, detail::assert_handler{},
                         "different type stored in union");
        }

        using storage_t = detail::aligned_union_t<Types...>;
        storage_t storage_;
        type_id   cur_type_;
    };

    /// \exclude
    template <typename... Types>
    constexpr typename tagged_union<Types...>::type_id tagged_union<Types...>::invalid_type;

    /// \exclude
    namespace detail
    {
        template <class Union>
        class destroy_union;

        template <typename... Types>
        class destroy_union<tagged_union<Types...>>
        {
        public:
            static void destroy(tagged_union<Types...>& u) noexcept
            {
                auto idx = static_cast<std::size_t>(u.type()) - 1u;
                DEBUG_ASSERT(idx < sizeof...(Types), detail::assert_handler{});
                callbacks[idx](u);
            }

        private:
            template <typename T>
            static void destroy_impl(tagged_union<Types...>& u) noexcept
            {
                u.destroy(union_type<T>{});
            }

            using callback_type                        = void (*)(tagged_union<Types...>&);
            static constexpr callback_type callbacks[] = {&destroy_impl<Types>...};
        };
        template <typename... Types>
        constexpr typename destroy_union<tagged_union<Types...>>::callback_type
            destroy_union<tagged_union<Types...>>::callbacks[];

        template <class Union>
        class copy_union;

        template <typename... Types>
        class copy_union<tagged_union<Types...>>
        {
        public:
            static void copy(tagged_union<Types...>& dest, const tagged_union<Types...>& org)
            {
                DEBUG_ASSERT(!dest.has_value(), detail::assert_handler{});

                auto idx = static_cast<std::size_t>(org.type()) - 1u;
                DEBUG_ASSERT(idx < sizeof...(Types), detail::assert_handler{});
                callbacks[idx](dest, org);
            }

        private:
            template <typename T>
            static void copy_impl(tagged_union<Types...>& dest, const tagged_union<Types...>& org)
            {
                dest.emplace(union_type<T>{}, org.value(union_type<T>{}));
            }

            using callback_type = void (*)(tagged_union<Types...>&, const tagged_union<Types...>&);
            static constexpr callback_type callbacks[] = {&copy_impl<Types>...};
        };
        template <typename... Types>
        constexpr typename copy_union<tagged_union<Types...>>::callback_type
            copy_union<tagged_union<Types...>>::callbacks[];

        template <class Union>
        class move_union;

        template <typename... Types>
        class move_union<tagged_union<Types...>>
        {
        public:
            static void move(tagged_union<Types...>& dest, tagged_union<Types...>&& org)
            {
                DEBUG_ASSERT(!dest.has_value(), detail::assert_handler{});

                auto idx = static_cast<std::size_t>(org.type()) - 1u;
                DEBUG_ASSERT(idx < sizeof...(Types), detail::assert_handler{});
                callbacks[idx](dest, std::move(org));
            }

        private:
            template <typename T>
            static void move_impl(tagged_union<Types...>& dest, tagged_union<Types...>&& org)
            {
                dest.emplace(union_type<T>{}, std::move(org).value(union_type<T>{}));
            }

            using callback_type = void (*)(tagged_union<Types...>&, tagged_union<Types...>&&);
            static constexpr callback_type callbacks[] = {&move_impl<Types>...};
        };
        template <typename... Types>
        constexpr typename move_union<tagged_union<Types...>>::callback_type
            move_union<tagged_union<Types...>>::callbacks[];
    } // namespace detail

    /// \effects Destroys the type currently stored in the [ts::tagged_union](),
    /// by calling `u.destroy(union_type<T>{})`.
    /// \requires The union must currently store a type,
    /// i.e. `has_value()` must return `true`.
    /// \module variant
    template <typename... Types>
    void destroy(tagged_union<Types...>& u) noexcept
    {
        detail::destroy_union<tagged_union<Types...>>::destroy(u);
    }

    /// \effects Copies the type currently stored in one [ts::tagged_union]() to another.
    /// This is equivalent to calling `dest.emplace(union_type<T>{}, org.value(union_type<T>{}))` (1)/
    /// `dest.emplace(union_type<T>{}, std::move(org).value(union_type<T>{}))` (2),
    /// where `T` is the type currently stored in the union.
    /// \throws Anything by the copy/move constructor in which case nothing has changed.
    /// \requires `dest` must not store a type, but `org` must have one,
    /// and all types must be copyable/moveable.
    /// \group union_copy_move
    /// \module variant
    /// \unique_name copy_union
    template <typename... Types>
    void copy(tagged_union<Types...>& dest, const tagged_union<Types...>& org)
    {
        detail::copy_union<tagged_union<Types...>>::copy(dest, org);
    }

    /// \group union_copy_move
    /// \module variant
    /// \unique_name move_union
    template <typename... Types>
    void move(tagged_union<Types...>& dest, tagged_union<Types...>&& org)
    {
        detail::move_union<tagged_union<Types...>>::move(dest, std::move(org));
    }
} // namespace type_safe

#endif // TYPE_SAFE_TAGGED_UNION_HPP_INCLUDED
<|endoftext|>


<commit_before>
/*!
	\file
	\brief Stream interface.

	\author Igor P. Mironchik (imironchick at gmail dot com).

	Copyright (c) 2011 Igor P. Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef EXCEL__STREAM_HPP__INCLUDED
#define EXCEL__STREAM_HPP__INCLUDED

namespace Excel {

//
// Stream
//

//! Stream interface.
class Stream {
public:
	//! Byte order identifier.
	enum ByteOrder {
		//! Big-Endian.
		BigEndian,
		//! Little-Endian.
		LittleEndian
	}; // enum ByteOrder

	explicit Stream( ByteOrder byteOrder );
	virtual ~Stream();

	Stream & operator = ( const Stream & stream );

	//! \return Byte order in the stream.
	ByteOrder byteOrder() const;

	//! Read one byte from the stream.
	virtual char getByte();

	//! \return true if EOF reached.
	virtual bool eof() const;

	//! Seek type.
	enum SeekType {
		//! Seek from the beginning of the stream.
		FromBeginning,
		//! Seek from the current position in the stream.
		FromCurrent,
		//! Seek from the end of the stream.
		FromEnd
	}; // enum SeekType

	//! Seek stream to new position.
	virtual void seek( int pos, SeekType type = FromBeginning );

	//! \return Position in the stream.
	virtual int pos();

	//! Read data from the stream.
	template< typename Type >
	void read( Type & retVal, int bytes = 0 )
	{
		retVal = Type(0);
		if( bytes == 0 ) bytes = sizeof( Type );

		for( int i = 0; i < bytes; ++i )
		{
			Type c = (Type)(unsigned char) getByte();

			#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
				if( m_byteOrder == BigEndian )
					retVal |= ( c << 8 * ( bytes - i ) );
				else
					retVal |= ( c << 8 * i );
			#else
				if( m_byteOrder == LittleEndian )
					retVal |= ( c << 8 * ( bytes - i ) );
				else
					retVal |= ( c << 8 * i );
			#endif
		}
	}

private:
	//! Byte order.
	ByteOrder m_byteOrder;
}; // class Stream

} /* namespace Excel */

#endif // EXCEL__STREAM_HPP__INCLUDED
<commit_msg>Fixed error of determine of the system byte order. Were used Q_BYTE_ORDER macro wich was not defined.<commit_after>
/*!
	\file
	\brief Stream interface.

	\author Igor P. Mironchik (imironchick at gmail dot com).

	Copyright (c) 2011 Igor P. Mironchik

	Permission is hereby granted, free of charge, to any person
	obtaining a copy of this software and associated documentation
	files (the "Software"), to deal in the Software without
	restriction, including without limitation the rights to use,
	copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the
	Software is furnished to do so, subject to the following
	conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
	OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef EXCEL__STREAM_HPP__INCLUDED
#define EXCEL__STREAM_HPP__INCLUDED

namespace Excel {

//
// Stream
//

//! Stream interface.
class Stream {
public:
	//! Byte order identifier.
	enum ByteOrder {
		//! Big-Endian.
		BigEndian,
		//! Little-Endian.
		LittleEndian
	}; // enum ByteOrder

private:

	//
	// SystemByteOrder
	//

	//! System's byte order.
	class SystemByteOrder {
	public:
		static ByteOrder byteOrder()
		{
			static const short int word = 0x0001;
			static const char * byte = (const char *) &word;

			return ( byte[0] ? LittleEndian : BigEndian );
		}
	}; // class SystemByteOrder

public:

	explicit Stream( ByteOrder byteOrder );
	virtual ~Stream();

	Stream & operator = ( const Stream & stream );

	//! \return Byte order in the stream.
	ByteOrder byteOrder() const;

	//! Read one byte from the stream.
	virtual char getByte();

	//! \return true if EOF reached.
	virtual bool eof() const;

	//! Seek type.
	enum SeekType {
		//! Seek from the beginning of the stream.
		FromBeginning,
		//! Seek from the current position in the stream.
		FromCurrent,
		//! Seek from the end of the stream.
		FromEnd
	}; // enum SeekType

	//! Seek stream to new position.
	virtual void seek( int pos, SeekType type = FromBeginning );

	//! \return Position in the stream.
	virtual int pos();

	//! Read data from the stream.
	template< typename Type >
	void read( Type & retVal, int bytes = 0 )
	{
		retVal = Type(0);
		if( bytes == 0 ) bytes = sizeof( Type );

		for( int i = 0; i < bytes; ++i )
		{
			Type c = (Type)(unsigned char) getByte();

			if( SystemByteOrder::byteOrder() != m_byteOrder )
				retVal |= ( c << 8 * ( bytes - i ) );
			else
				retVal |= ( c << 8 * i );
		}
	}

private:
	//! Byte order.
	ByteOrder m_byteOrder;
}; // class Stream

} /* namespace Excel */

#endif // EXCEL__STREAM_HPP__INCLUDED
<|endoftext|>


<commit_before>/**
 * @file llhandmotion.cpp
 * @brief Implementation of LLHandMotion class.
 *
 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "linden_common.h"

#include "llhandmotion.h"
#include "llcharacter.h"
#include "m3math.h"

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------

const char *gHandPoseNames[LLHandMotion::NUM_HAND_POSES] =  /* Flawfinder: ignore */
{
	"",
	"Hands_Relaxed",
	"Hands_Point",
	"Hands_Fist",
	"Hands_Relaxed_L",
	"Hands_Point_L",
	"Hands_Fist_L",
	"Hands_Relaxed_R",
	"Hands_Point_R",
	"Hands_Fist_R",
	"Hands_Salute_R",
	"Hands_Typing",
	"Hands_Peace_R",
	"Hands_Spread_R"
};

const F32 HAND_MORPH_BLEND_TIME = 0.2f;

//-----------------------------------------------------------------------------
// LLHandMotion()
// Class Constructor
//-----------------------------------------------------------------------------
LLHandMotion::LLHandMotion(const LLUUID &id) : LLMotion(id)
{
	mCharacter = NULL;
	mLastTime = 0.f;
	mCurrentPose = HAND_POSE_RELAXED;
	mNewPose = HAND_POSE_RELAXED;
	mName = "hand_motion";

	//RN: flag hand joint as highest priority for now, until we implement a proper animation track
	mJointSignature[0][LL_HAND_JOINT_NUM] = 0xff;
	mJointSignature[1][LL_HAND_JOINT_NUM] = 0xff;
	mJointSignature[2][LL_HAND_JOINT_NUM] = 0xff;
}

//-----------------------------------------------------------------------------
// ~LLHandMotion()
// Class Destructor
//-----------------------------------------------------------------------------
LLHandMotion::~LLHandMotion()
{
}

//-----------------------------------------------------------------------------
// LLHandMotion::onInitialize(LLCharacter *character)
//-----------------------------------------------------------------------------
LLMotion::LLMotionInitStatus LLHandMotion::onInitialize(LLCharacter *character)
{
	mCharacter = character;

	return STATUS_SUCCESS;
}

//-----------------------------------------------------------------------------
// LLHandMotion::onActivate()
//-----------------------------------------------------------------------------
BOOL LLHandMotion::onActivate()
{
	LLPolyMesh *upperBodyMesh = mCharacter->getUpperBodyMesh();

	if (upperBodyMesh)
	{
		// Note: 0 is the default
		for (S32 i = 1; i < LLHandMotion::NUM_HAND_POSES; i++)
		{
			mCharacter->setVisualParamWeight(gHandPoseNames[i], 0.f);
		}
		mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
		mCharacter->updateVisualParams();
	}
	return TRUE;
}

//-----------------------------------------------------------------------------
// LLHandMotion::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask)
{
	eHandPose *requestedHandPose;

	F32 timeDelta = time - mLastTime;
	mLastTime = time;

	requestedHandPose = (eHandPose *)mCharacter->getAnimationData("Hand Pose");
	// check to see if requested pose has changed
	if (!requestedHandPose)
	{
		if (mNewPose != HAND_POSE_RELAXED && mNewPose != mCurrentPose)
		{
			mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
		}
		mNewPose = HAND_POSE_RELAXED;
	}
	else
	{
		// this is a new morph we didn't know about before
		if (*requestedHandPose != mNewPose && mNewPose != mCurrentPose && mNewPose != HAND_POSE_SPREAD)
		{
			mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
		}
		mNewPose = *requestedHandPose;
	}

	mCharacter->removeAnimationData("Hand Pose");
	mCharacter->removeAnimationData("Hand Pose Priority");

//	if (requestedHandPose)
//		llinfos << "Hand Pose " << *requestedHandPose << llendl;

	// if we are still blending...
	if (mCurrentPose != mNewPose)
	{
		F32 incomingWeight = 1.f;
		F32 outgoingWeight = 0.f;

		if (mNewPose != HAND_POSE_SPREAD)
		{
			incomingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mNewPose]);
			incomingWeight += (timeDelta / HAND_MORPH_BLEND_TIME);
			incomingWeight = llclamp(incomingWeight, 0.f, 1.f);
			mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], incomingWeight);
		}

		if (mCurrentPose != HAND_POSE_SPREAD)
		{
			outgoingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mCurrentPose]);
			outgoingWeight -= (timeDelta / HAND_MORPH_BLEND_TIME);
			outgoingWeight = llclamp(outgoingWeight, 0.f, 1.f);
			mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], outgoingWeight);
		}

		mCharacter->updateVisualParams();

		if (incomingWeight == 1.f && outgoingWeight == 0.f)
		{
			mCurrentPose = mNewPose;
		}
	}

	return TRUE;
}

//-----------------------------------------------------------------------------
// LLHandMotion::onDeactivate()
//-----------------------------------------------------------------------------
void LLHandMotion::onDeactivate()
{
}

//-----------------------------------------------------------------------------
// LLHandMotion::getHandPoseName()
//-----------------------------------------------------------------------------
std::string LLHandMotion::getHandPoseName(eHandPose pose)
{
	if ((S32)pose < LLHandMotion::NUM_HAND_POSES && (S32)pose >= 0)
	{
		return std::string(gHandPoseNames[pose]);
	}
	return LLStringUtil::null;
}

LLHandMotion::eHandPose LLHandMotion::getHandPose(std::string posename)
{
	for (S32 pose = 0; pose < LLHandMotion::NUM_HAND_POSES; ++pose)
	{
		if (gHandPoseNames[pose] == posename)
		{
			return (eHandPose)pose;
		}
	}
	return (eHandPose)0;
}

// End
<commit_msg>Fix crash in LLHandMotion::onUpdate when motion id is out of range.<commit_after>/**
 * @file llhandmotion.cpp
 * @brief Implementation of LLHandMotion class.
 *
 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "linden_common.h"

#include "llhandmotion.h"
#include "llcharacter.h"
#include "m3math.h"

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------

const char *gHandPoseNames[LLHandMotion::NUM_HAND_POSES] =  /* Flawfinder: ignore */
{
	"",
	"Hands_Relaxed",
	"Hands_Point",
	"Hands_Fist",
	"Hands_Relaxed_L",
	"Hands_Point_L",
	"Hands_Fist_L",
	"Hands_Relaxed_R",
	"Hands_Point_R",
	"Hands_Fist_R",
	"Hands_Salute_R",
	"Hands_Typing",
	"Hands_Peace_R",
	"Hands_Spread_R"
};

const F32 HAND_MORPH_BLEND_TIME = 0.2f;

//-----------------------------------------------------------------------------
// LLHandMotion()
// Class Constructor
//-----------------------------------------------------------------------------
LLHandMotion::LLHandMotion(const LLUUID &id) : LLMotion(id)
{
	mCharacter = NULL;
	mLastTime = 0.f;
	mCurrentPose = HAND_POSE_RELAXED;
	mNewPose = HAND_POSE_RELAXED;
	mName = "hand_motion";

	//RN: flag hand joint as highest priority for now, until we implement a proper animation track
	mJointSignature[0][LL_HAND_JOINT_NUM] = 0xff;
	mJointSignature[1][LL_HAND_JOINT_NUM] = 0xff;
	mJointSignature[2][LL_HAND_JOINT_NUM] = 0xff;
}

//-----------------------------------------------------------------------------
// ~LLHandMotion()
// Class Destructor
//-----------------------------------------------------------------------------
LLHandMotion::~LLHandMotion()
{
}

//-----------------------------------------------------------------------------
// LLHandMotion::onInitialize(LLCharacter *character)
//-----------------------------------------------------------------------------
LLMotion::LLMotionInitStatus LLHandMotion::onInitialize(LLCharacter *character)
{
	mCharacter = character;

	return STATUS_SUCCESS;
}

//-----------------------------------------------------------------------------
// LLHandMotion::onActivate()
//-----------------------------------------------------------------------------
BOOL LLHandMotion::onActivate()
{
	LLPolyMesh *upperBodyMesh = mCharacter->getUpperBodyMesh();

	if (upperBodyMesh)
	{
		// Note: 0 is the default
		for (S32 i = 1; i < LLHandMotion::NUM_HAND_POSES; i++)
		{
			mCharacter->setVisualParamWeight(gHandPoseNames[i], 0.f);
		}
		mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
		mCharacter->updateVisualParams();
	}
	return TRUE;
}

//-----------------------------------------------------------------------------
// LLHandMotion::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask)
{
	eHandPose *requestedHandPose;

	F32 timeDelta = time - mLastTime;
	mLastTime = time;

	requestedHandPose = (eHandPose *)mCharacter->getAnimationData("Hand Pose");
	// check to see if requested pose has changed
	if (!requestedHandPose)
	{
		if (mNewPose != HAND_POSE_RELAXED && mNewPose != mCurrentPose)
		{
			mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
		}
		mNewPose = HAND_POSE_RELAXED;
	}
	else
	{
		// <FS:ND> Sometimes we seem to get garbage here, with poses that are out of bounds.

		// this is a new morph we didn't know about before
		//		if ( *requestedHandPose != mNewPose && mNewPose != mCurrentPose && mNewPose != HAND_POSE_SPREAD)
		if (*requestedHandPose >= 0 && *requestedHandPose < NUM_HAND_POSES && *requestedHandPose != mNewPose && mNewPose != mCurrentPose && mNewPose != HAND_POSE_SPREAD)
		{
			mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], 0.f);
		}
		//		mNewPose = *requestedHandPose;
		mNewPose = static_cast<eHandPose> ( llclamp( static_cast<int>(*requestedHandPose), 0, NUM_HAND_POSES-1 ) );

		// </FS:ND>
	}

	mCharacter->removeAnimationData("Hand Pose");
	mCharacter->removeAnimationData("Hand Pose Priority");

//	if (requestedHandPose)
//		llinfos << "Hand Pose " << *requestedHandPose << llendl;

	// if we are still blending...
	if (mCurrentPose != mNewPose)
	{
		F32 incomingWeight = 1.f;
		F32 outgoingWeight = 0.f;

		if (mNewPose != HAND_POSE_SPREAD)
		{
			incomingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mNewPose]);
			incomingWeight += (timeDelta / HAND_MORPH_BLEND_TIME);
			incomingWeight = llclamp(incomingWeight, 0.f, 1.f);
			mCharacter->setVisualParamWeight(gHandPoseNames[mNewPose], incomingWeight);
		}

		if (mCurrentPose != HAND_POSE_SPREAD)
		{
			outgoingWeight = mCharacter->getVisualParamWeight(gHandPoseNames[mCurrentPose]);
			outgoingWeight -= (timeDelta / HAND_MORPH_BLEND_TIME);
			outgoingWeight = llclamp(outgoingWeight, 0.f, 1.f);
			mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], outgoingWeight);
		}

		mCharacter->updateVisualParams();

		if (incomingWeight == 1.f && outgoingWeight == 0.f)
		{
			mCurrentPose = mNewPose;
		}
	}

	return TRUE;
}

//-----------------------------------------------------------------------------
// LLHandMotion::onDeactivate()
//-----------------------------------------------------------------------------
void LLHandMotion::onDeactivate()
{
}

//-----------------------------------------------------------------------------
// LLHandMotion::getHandPoseName()
//-----------------------------------------------------------------------------
std::string LLHandMotion::getHandPoseName(eHandPose pose)
{
	if ((S32)pose < LLHandMotion::NUM_HAND_POSES && (S32)pose >= 0)
	{
		return std::string(gHandPoseNames[pose]);
	}
	return LLStringUtil::null;
}

LLHandMotion::eHandPose LLHandMotion::getHandPose(std::string posename)
{
	for (S32 pose = 0; pose < LLHandMotion::NUM_HAND_POSES; ++pose)
	{
		if (gHandPoseNames[pose] == posename)
		{
			return (eHandPose)pose;
		}
	}
	return (eHandPose)0;
}

// End
<|endoftext|>