<commit_before>#include <iostream>
#include <sstream>
#include <string>

#include <unistd.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <cstdlib>
#include <cstring>

#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 "terminate_message.h"

#include "constants.h"
#include "network.h"
#include "helper_functions.h"

using namespace std;

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

static map<procedure_signature, list<server_info *>, ps_compare> procLocDict;
static list<server_function_info *> roundRobinList;
static list<server_info *> serverList;

static bool onSwitch = true;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/

void mapPrint(){
  cout << "procLocDict size: "<<procLocDict.size() << endl;
  cout << "Map Print: ";
  for(map<procedure_signature, list<server_info *>, ps_compare> ::const_iterator it = procLocDict.begin();
   it != procLocDict.end(); it++){

    cout << it->first.name << ", " ;
  }

  cout << endl;
}

void roundRobinPrint(){
  cout << "roundRobin Print: ";
  for(list<server_function_info *> ::const_iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
    cout <<(*it)->si->server_identifier << ", "<<(*it)->si->port << ", "<<(*it)->ps->name << endl;
  }
}

void serverListPrint(){
  cout << "serverList Print: " << endl;
  for(list<server_info *> ::const_iterator it = serverList.begin(); it != serverList.end(); it++){
    cout << (*it)->server_identifier << ", " <<  (*it)->port << ", " <<  (*it)->socket<< endl;
  }
}

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();

  cout << "We are trying to register: " << name  << ", " << server_identifier << ", " << port << endl;

  procedure_signature key(name, argTypes);

  int status = 0;

  //if 'key' dosnt exist in map, add it to the map and round robin
	if (procLocDict.find(key) == procLocDict.end()) {
    //The purpose of this function is so we can have copy of the argTypes that not the original
    int *memArgTypes = copyArgTypes(argTypes);

    key = procedure_signature(name, memArgTypes);
    procLocDict[key] = list<server_info *>();

    //This is bad we shouldn't need a newKey and we should be able to use the key above
    //due to &* reasones I made a variable newKey for the 'info' object
    procedure_signature * newKey = new procedure_signature(name, memArgTypes);
    server_info * entry = new server_info(server_identifier, port, sock);
    server_function_info * info = new server_function_info(entry, newKey);

    //Adding to roundRobinList if server is not found
    roundRobinList.push_back(info);

    //Adding to serverList if server is not found
    bool serverExist = false;
    for (list<server_info *>::iterator it = serverList.begin(); it != serverList.end(); it++) {

      if( (*it)->server_identifier == entry->server_identifier && (*it)->port == entry->port &&  (*it)->socket == entry->socket){
          serverExist = true;
          break;
        }
    }

    //cout << "entry->server_identifier: " <<entry->server_identifier << endl;
    //cout << "entry->port: " <<entry->port << endl;
    //cout << "entry->socket: " << entry->socket << endl;

    //cout << "sock: " << sock << endl;

    if(!serverExist){
      serverList.push_back(entry);
    }

  } else {
    bool sameLoc = false;
    list<server_info *> hostList = procLocDict[key];

    for (list<server_info *>::iterator it = hostList.begin(); it != hostList.end(); it++) {
      if((*it)->server_identifier == server_identifier && (*it)->port == port  && (*it)->socket == sock){
        //If they have the same socket, then must be same server_address/port
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something, maybe we should keep
        cout << "Exact same proc and loc" << endl;
        sameLoc = true;
      }
    }

  	if(!sameLoc){ //same procedure different socket
       cout << "same proc different loc" << endl;

       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList.push_back(new_msg_loc);

       int *newArgTypes = copyArgTypes(argTypes);

       procedure_signature * useFulKey = new procedure_signature(name, newArgTypes);
       server_function_info * info = new server_function_info(new_msg_loc, useFulKey);

       //Adding to roundRobinList if server is not found
       roundRobinList.push_back(info);
    }
  }

  //mapPrint();
  roundRobinPrint();
  //serverListPrint();

  RegisterSuccessMessage regSuccessMsg = RegisterSuccessMessage(status);
  Segment regSuccessSeg = Segment(regSuccessMsg.getLength(), MSG_TYPE_REGISTER_SUCCESS, &regSuccessMsg);
  regSuccessSeg.send(sock);

  cout << "sock: " << sock << endl;
}

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

  bool exist = false;
  string serverIdToPushBack;
  int portToPushBack;
  int socketToPushBack;

  //cout << "Hunted name names: " << message->getName() << endl;

	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
    //If the name are the same and argTypes
    //cout << "Iterator names: " << (*it)->ps->name << endl;

    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){
      exist = true;

      cout << "Sending to server: " << (*it)->si->server_identifier << ", "<< (*it)->si->port<< endl;

      serverIdToPushBack = (*it)->si->server_identifier;
      portToPushBack = (*it)->si->port;
      socketToPushBack = (*it)->si->socket;

      LocSuccessMessage locSuccessMsg = LocSuccessMessage((*it)->si->server_identifier.c_str(), (*it)->si->port);
      Segment locSuccessSeg = Segment(locSuccessMsg.getLength(), MSG_TYPE_LOC_SUCCESS, &locSuccessMsg);
      locSuccessSeg.send(sock);

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

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

      /*
       if((*it)->si->server_identifier == serverIdToPushBack && (*it)->si->port == portToPushBack && (*it)->si->socket == socketToPushBack){
          roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
       }
      */

        cout << "What the heck: "<< (*it)->si->port << ", " << portToPushBack << endl;
       if((*it)->si->port == portToPushBack && (*it)->si->socket == socketToPushBack){
          roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
       }

    }
    //roundRobinPrint();
  }else {
    int reasoncode = -5; // Need actual reasoncode
    LocFailureMessage locFailMsg = LocFailureMessage(reasoncode);
    Segment locFailSeg = Segment(locFailMsg.getLength(), MSG_TYPE_LOC_FAILURE, &locFailMsg);
    locFailSeg.send(sock);
  }
}

void binder_terminate_handler() {
  cout << "Binder set to execute" << endl;

  for (list<server_info *>::const_iterator it = serverList.begin(); it != serverList.end(); it++) {
    cout << "Terminating server: " << (*it)->server_identifier << ", " <<  (*it)->port << ", " <<  (*it)->socket<< endl;
    TerminateMessage termMsg = TerminateMessage();
    Segment termSeg = Segment(termMsg.getLength(), MSG_TYPE_TERMINATE, &termMsg);
    termSeg.send((*it)->socket);
  }

  onSwitch = false;

}

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

    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){

    //cout << "Loc Request" << endl;

    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);

    location_request_handler(lqm, sock);

  }else if (segment->getType() == MSG_TYPE_TERMINATE){

    cout << "Terminate Request" <<endl;

    binder_terminate_handler();
  }

	return retval;
}

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

  /*
   * Clears all entries from the all sockets set and the read
   * sockets set
   */
  FD_ZERO(&allSockets);
  FD_ZERO(&readSockets);

  /*
   * Creates the welcome socket, adds it to the all sockets set and
   * sets it as the maximum socket so far
   */
  int welcomeSocket = createSocket();
  int status = setUpToListen(welcomeSocket);
  FD_SET(welcomeSocket, &allSockets);
  int maxSocket = welcomeSocket;

  /*
   * Prints the binder address and the binder port on the binder's
   * standard output
   */
  cout << "BINDER_ADDRESS " << getHostAddress() << endl;
  cout << "BINDER_PORT " << getSocketPort(welcomeSocket) << endl;

  while (onSwitch) {
    readSockets = allSockets;

    // Checks if some of the sockets are ready to be read from
    int result = select(maxSocket + 1, &readSockets, 0, 0, 0);
    if (result < 0) {
      continue;
    }

    for (int i = 0; i <= maxSocket; i++) {
      if (!FD_ISSET(i, &readSockets)) {
        continue;
      }

      if (i == welcomeSocket) {

        /*
         * Creates the connection socket when a connection is made
         * to the welcome socket
         */
        int connectionSocket = acceptConnection(i);
        if (connectionSocket < 0) {
          continue;
        }

        //cout << "WE heard from connectionSocket: " << connectionSocket << endl;
        // Adds the connection socket to the all sockets set
        FD_SET(connectionSocket, &allSockets);

        /*
         * Sets the connection socket as the maximum socket so far
         * if necessary
         */
        if (connectionSocket > maxSocket) {
          maxSocket = connectionSocket;
        }

      } else {

        /*
         * Creates a segment to receive data from the client/server and
         * reads into it from the connection socket
         */
        Segment *segment = 0;
        result = 0;
        result = Segment::receive(i, segment);
        if (result < 0) {
          /*
           * Closes the connection socket and removes it from the
           * all sockets set
           */
          destroySocket(i);
          FD_CLR(i, &allSockets);
          continue;
        }

        request_handler(segment, i);
      }
    }
  }

  // Destroys the welcome socket
  destroySocket(welcomeSocket);
}
<commit_msg>changes<commit_after>#include <iostream>
#include <sstream>
#include <string>

#include <unistd.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <cstdlib>
#include <cstring>

#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 "terminate_message.h"

#include "constants.h"
#include "network.h"
#include "helper_functions.h"

using namespace std;

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

static map<procedure_signature, list<server_info *>, ps_compare> procLocDict;
static list<server_function_info *> roundRobinList;
static list<server_info *> serverList;

static bool onSwitch = true;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/

void mapPrint(){
  cout << "procLocDict size: "<<procLocDict.size() << endl;
  cout << "Map Print: ";
  for(map<procedure_signature, list<server_info *>, ps_compare> ::const_iterator it = procLocDict.begin();
   it != procLocDict.end(); it++){

    cout << it->first.name << ", " ;
  }

  cout << endl;
}

void roundRobinPrint(){
  cout << "roundRobin Print: ";
  for(list<server_function_info *> ::const_iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
    cout <<(*it)->si->server_identifier << ", "<<(*it)->si->port << ", "<<(*it)->ps->name << endl;
  }
}

void serverListPrint(){
  cout << "serverList Print: " << endl;
  for(list<server_info *> ::const_iterator it = serverList.begin(); it != serverList.end(); it++){
    cout << (*it)->server_identifier << ", " <<  (*it)->port << ", " <<  (*it)->socket<< endl;
  }
}

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();

  cout << "We are trying to register: " << name  << ", " << server_identifier << ", " << port << endl;

  procedure_signature key(name, argTypes);

  int status = 0;

  //if 'key' dosnt exist in map, add it to the map and round robin
	if (procLocDict.find(key) == procLocDict.end()) {
    //The purpose of this function is so we can have copy of the argTypes that not the original
    int *memArgTypes = copyArgTypes(argTypes);

    key = procedure_signature(name, memArgTypes);
    procLocDict[key] = list<server_info *>();

    //This is bad we shouldn't need a newKey and we should be able to use the key above
    //due to &* reasones I made a variable newKey for the 'info' object
    procedure_signature * newKey = new procedure_signature(name, memArgTypes);
    server_info * entry = new server_info(server_identifier, port, sock);
    server_function_info * info = new server_function_info(entry, newKey);

    //Adding to roundRobinList if server is not found
    roundRobinList.push_back(info);

    //Adding to serverList if server is not found
    bool serverExist = false;
    for (list<server_info *>::iterator it = serverList.begin(); it != serverList.end(); it++) {

      if( (*it)->server_identifier == entry->server_identifier && (*it)->port == entry->port &&  (*it)->socket == entry->socket){
          serverExist = true;
          break;
        }
    }

    //cout << "entry->server_identifier: " <<entry->server_identifier << endl;
    //cout << "entry->port: " <<entry->port << endl;
    //cout << "entry->socket: " << entry->socket << endl;

    //cout << "sock: " << sock << endl;

    if(!serverExist){
      serverList.push_back(entry);
    }

  } else {
    bool sameLoc = false;
    list<server_info *> hostList = procLocDict[key];

    for (list<server_info *>::iterator it = hostList.begin(); it != hostList.end(); it++) {
      if((*it)->server_identifier == server_identifier && (*it)->port == port  && (*it)->socket == sock){
        //If they have the same socket, then must be same server_address/port
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something, maybe we should keep
        cout << "Exact same proc and loc" << endl;
        sameLoc = true;
      }
    }

  	if(!sameLoc){ //same procedure different socket
       cout << "same proc different loc" << endl;

       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList.push_back(new_msg_loc);

       int *newArgTypes = copyArgTypes(argTypes);

       procedure_signature * useFulKey = new procedure_signature(name, newArgTypes);
       server_function_info * info = new server_function_info(new_msg_loc, useFulKey);

       //Adding to roundRobinList if server is not found
       roundRobinList.push_back(info);
    }
  }

  //mapPrint();
  roundRobinPrint();
  //serverListPrint();

  RegisterSuccessMessage regSuccessMsg = RegisterSuccessMessage(status);
  Segment regSuccessSeg = Segment(regSuccessMsg.getLength(), MSG_TYPE_REGISTER_SUCCESS, &regSuccessMsg);
  regSuccessSeg.send(sock);

  cout << "sock: " << sock << endl;
}

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

  bool exist = false;
  string serverIdToPushBack;
  int portToPushBack;
  int socketToPushBack;

  //cout << "Hunted name names: " << message->getName() << endl;

	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){
    //If the name are the same and argTypes
    //cout << "Iterator names: " << (*it)->ps->name << endl;

    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){
      exist = true;

      cout << "Sending to server: " << (*it)->si->server_identifier << ", "<< (*it)->si->port<< endl;

      serverIdToPushBack = (*it)->si->server_identifier;
      portToPushBack = (*it)->si->port;
      socketToPushBack = (*it)->si->socket;

      LocSuccessMessage locSuccessMsg = LocSuccessMessage((*it)->si->server_identifier.c_str(), (*it)->si->port);
      Segment locSuccessSeg = Segment(locSuccessMsg.getLength(), MSG_TYPE_LOC_SUCCESS, &locSuccessMsg);
      locSuccessSeg.send(sock);

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

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

      /*
       if((*it)->si->server_identifier == serverIdToPushBack && (*it)->si->port == portToPushBack && (*it)->si->socket == socketToPushBack){
          roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
       }
      */

      cout << "What the heck: "<< (*it)->si->port << ", " << portToPushBack << ", " <<(*it)->si->socket << ", " << socketToPushBack<< endl;
       if((*it)->si->port == portToPushBack && (*it)->si->socket == socketToPushBack){
          cout <<"WTF WHILLIS" << end;
          roundRobinList.splice(roundRobinList.end(), roundRobinList, it);
       }

    }
    //roundRobinPrint();
  }else {
    int reasoncode = -5; // Need actual reasoncode
    LocFailureMessage locFailMsg = LocFailureMessage(reasoncode);
    Segment locFailSeg = Segment(locFailMsg.getLength(), MSG_TYPE_LOC_FAILURE, &locFailMsg);
    locFailSeg.send(sock);
  }
}

void binder_terminate_handler() {
  cout << "Binder set to execute" << endl;

  for (list<server_info *>::const_iterator it = serverList.begin(); it != serverList.end(); it++) {
    cout << "Terminating server: " << (*it)->server_identifier << ", " <<  (*it)->port << ", " <<  (*it)->socket<< endl;
    TerminateMessage termMsg = TerminateMessage();
    Segment termSeg = Segment(termMsg.getLength(), MSG_TYPE_TERMINATE, &termMsg);
    termSeg.send((*it)->socket);
  }

  onSwitch = false;

}

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

    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){

    //cout << "Loc Request" << endl;

    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);

    location_request_handler(lqm, sock);

  }else if (segment->getType() == MSG_TYPE_TERMINATE){

    cout << "Terminate Request" <<endl;

    binder_terminate_handler();
  }

	return retval;
}

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

  /*
   * Clears all entries from the all sockets set and the read
   * sockets set
   */
  FD_ZERO(&allSockets);
  FD_ZERO(&readSockets);

  /*
   * Creates the welcome socket, adds it to the all sockets set and
   * sets it as the maximum socket so far
   */
  int welcomeSocket = createSocket();
  int status = setUpToListen(welcomeSocket);
  FD_SET(welcomeSocket, &allSockets);
  int maxSocket = welcomeSocket;

  /*
   * Prints the binder address and the binder port on the binder's
   * standard output
   */
  cout << "BINDER_ADDRESS " << getHostAddress() << endl;
  cout << "BINDER_PORT " << getSocketPort(welcomeSocket) << endl;

  while (onSwitch) {
    readSockets = allSockets;

    // Checks if some of the sockets are ready to be read from
    int result = select(maxSocket + 1, &readSockets, 0, 0, 0);
    if (result < 0) {
      continue;
    }

    for (int i = 0; i <= maxSocket; i++) {
      if (!FD_ISSET(i, &readSockets)) {
        continue;
      }

      if (i == welcomeSocket) {

        /*
         * Creates the connection socket when a connection is made
         * to the welcome socket
         */
        int connectionSocket = acceptConnection(i);
        if (connectionSocket < 0) {
          continue;
        }

        //cout << "WE heard from connectionSocket: " << connectionSocket << endl;
        // Adds the connection socket to the all sockets set
        FD_SET(connectionSocket, &allSockets);

        /*
         * Sets the connection socket as the maximum socket so far
         * if necessary
         */
        if (connectionSocket > maxSocket) {
          maxSocket = connectionSocket;
        }

      } else {

        /*
         * Creates a segment to receive data from the client/server and
         * reads into it from the connection socket
         */
        Segment *segment = 0;
        result = 0;
        result = Segment::receive(i, segment);
        if (result < 0) {
          /*
           * Closes the connection socket and removes it from the
           * all sockets set
           */
          destroySocket(i);
          FD_CLR(i, &allSockets);
          continue;
        }

        request_handler(segment, i);
      }
    }
  }

  // Destroys the welcome socket
  destroySocket(welcomeSocket);
}
<|endoftext|>


<commit_before>#include <cstddef>
#include <cassert>
#include <new>
#include <type_traits>
#include <atomic>
#include <inttypes.h>
#include <stdio.h>

#include <thread>
#include <vector>
#include <iostream>

#include "tinfra/fmt.h"
#include "tinfra/stream.h"

template <typename T>
class atomic_segregated_memory_allocator {
    static_assert(sizeof(T) >= sizeof(int), "T shall be able to store int basic_linked_memory_pool ");

    T* const        buffer_start;
    const size_t    buffer_size;
    std::atomic<int> next_free;
    std::atomic<int> n_allocated;

public:
    atomic_segregated_memory_allocator(T* ptr, size_t size):
        buffer_start(ptr),
        buffer_size(size),
        next_free(0),
        n_allocated(0)
    {
        this->initialize_storage();
    }

    // C++-like allocator interface
    T* allocate() {
        int allocated_item = next_free.load();

        while( true ) {
            if( allocated_item == -1 ) {
                throw std::bad_alloc();
            }
            int new_next_free = indicator(allocated_item);
            assert(new_next_free != allocated_item);
            const bool change_succeded = next_free.compare_exchange_strong(allocated_item, new_next_free);
            if( !change_succeded ) {
                tprintf(tinfra::err, "allocate, retrying transaction\n");
                continue;
            }
            break;
        }
        ++n_allocated;
        return item_ptr(allocated_item);
    }
    void deallocate(T* p) {
        assert( p >= this->buffer_start && p < this->buffer_start + this->buffer_size);
        //assert( p % sizeof(T) == 0 );

        const int idx = (p - this->buffer_start);
        int       last_next_free = next_free.load();
        while( true ) {
            assert(last_next_free != idx);
            this->indicator(idx) = last_next_free;
                // this assertion sometimes fails, so we have some inconsistency
                // in free slot graph !!!
            const bool change_succeded = next_free.compare_exchange_strong(last_next_free, idx);
            if( !change_succeded ) {
                tprintf(tinfra::err, "deallocate, retrying transaction\n");
                continue;
            }
            break;
        }
        --n_allocated;
    }

    int allocated() const {
        int r = this->buffer_size;
        int i = this->next_free;
        while( i != -1 ) {
            i = indicator(i);
            r -= 1;
        }
        return r;
        //return this->n_allocated.load(std::memory_order_relaxed);
    }
private:
    void initialize_storage()
    {
        for( size_t i = 0; i < this->buffer_size; i++ ) {
            indicator(i) = i+1;
        }
        indicator(this->buffer_size-1) = -1;
        this->next_free = 0;
    }
    const int& indicator(int i) const {
        return * reinterpret_cast<int const*>(this->buffer_start + i);
    }
    int& indicator(int i) {
        return * reinterpret_cast<int*>(this->buffer_start + i);
    }
    T*   item_ptr(int i) {
        return this->buffer_start + i;
    }

};

template <typename T, size_t N>
struct static_atomic_segregated_memory_pool {
    typename std::aligned_storage<sizeof(T), alignof(T)>::type buffer[N];
    atomic_segregated_memory_allocator<T> allocator;

public:
    static_atomic_segregated_memory_pool():
        allocator(reinterpret_cast<T*>(buffer), N)
    { }

    // C++ allocator interface
    T* allocate() {
        return this->allocator.allocate();
    }

    void deallocate(T* p) {
        this->allocator.deallocate(p);
    }
    int allocated() const {
        return this->allocator.allocated();
    }
};

#define PPTR(name) ::printf("%s = %p\n", #name, name)

static_atomic_segregated_memory_pool<int, 1024> pool;

void test0()
{
    assert( pool.allocated() == 0);
    int* p = pool.allocate();
    assert( pool.allocated() == 1);
    pool.deallocate(p);
    assert( pool.allocated() == 0);
}

void test1()
{
    const int R = 1024;
    int* ptrs[R];
    assert( pool.allocated() == 0);

    for( int r = 0; r < R; r++ ) {
        ptrs[r] = pool.allocate();
        assert( pool.allocated() == r+1);
    }

    for( int r = 0; r < R; r++ ) {
        pool.deallocate(ptrs[r]);
        assert( pool.allocated() == 1024-(r+1));
    }

    assert( pool.allocated() == 0);
}

void f(int T)
{
    const int R = 1024;
    const int N = 10;
    int* ptr[N];
    for( int r = 0; r < R; r++ ) {
        //tinfra::tprintf(tinfra::err, "T[%i] before iter %i pool size %i\n", T, r, pool.allocated());
        for( int i = 0; i < N; ++i ) {
            ptr[i] = pool.allocate();
            //tinfra::tprintf(tinfra::err, "T[%i] allocated %i\n", T, ptr[i]);
        }

        for( int i = 0; i < N; ++i ) {
            //tinfra::tprintf(tinfra::err, "T[%i] deallocating %i\n", T, ptr[i]);
            pool.deallocate(ptr[i]);
        }
        //tinfra::tprintf(tinfra::err, "T[%i] before iter %i pool size %i\n", T, r, pool.allocated());
    }
}

void test3()
{
    assert( pool.allocated() == 0);
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f, n);
    }
    for (auto& t : v) {
        t.join();
    }
    tinfra::tprintf(tinfra::err, "T[main] after test pool size %i\n",pool.allocated());
}

int main()
{
    test0();
    test1();
    test3();
}<commit_msg>atomic_segregated_memory_pool: debugging it ... still buggy (ABA) on allocate<commit_after>#include <cstddef>
#include <cassert>
#include <new>
#include <type_traits>
#include <atomic>
#include <inttypes.h>
#include <stdio.h>
#include <unistd.h>

#include <thread>
#include <vector>
#include <iostream>

#include "tinfra/fmt.h"
#include "tinfra/stream.h"

int thread_count = 0;
thread_local int thread_log_idx;

std::string get_thread_string()
{
    std::string foo(thread_count, '.');
    foo[thread_log_idx] = '|';
    return tinfra::tsprintf("%i-%s", std::this_thread::get_id(), foo);
}

template <typename T>
std::string vector_to_string(T const& v)
{
    std::ostringstream foo;
    foo << "[";
    for( int i = 0; i < v.size(); ++i ) {
        if( i != 0 ) {
            foo << ", ";
        }
        foo << v[i];
    }
    foo << "]";
    return foo.str();
}

#ifdef USE_STD_ATOMIC

#define ATOMMOO std::atomic

#else
#include <mutex>

template <typename T>
class my_mutex_based_fake_atomic {
    T protected_var;
    mutable std::mutex mux;
public:
    my_mutex_based_fake_atomic():
        protected_var()
    {
    }

    my_mutex_based_fake_atomic(T v):
        protected_var(v)
    {
    }

    my_mutex_based_fake_atomic<T>& operator=(T v) {
        std::lock_guard<std::mutex> g(this->mux);
        protected_var = v;
        return *this;
    }

    my_mutex_based_fake_atomic<T>& operator++() { // prefix ++
        std::lock_guard<std::mutex> g(this->mux);
        protected_var++;
        return *this;
    }

    my_mutex_based_fake_atomic<T>& operator--() { // prefix ++
        std::lock_guard<std::mutex> g(this->mux);
        protected_var--;
        return *this;
    }
    /*
    my_mutex_based_fake_atomic<T> operator++(int) {
        std::lock_guard<std::mutex> g(this->mux);
        my_mutex_based_fake_atomic<T> result(protected_var);
        protected_var++;
        return *this;
    }
    */

    T load() const {
        std::lock_guard<std::mutex> g(this->mux);
        return protected_var;
    }

    bool compare_exchange_strong(T& expected, T desired) {
        std::lock_guard<std::mutex> g(this->mux);
        if( protected_var == expected ) {
            protected_var = desired;
            tprintf(tinfra::err, "T[%i]: compare_exchange_strong commited %i (expected=%i)\n", get_thread_string(), desired, expected);
            return true;
        } else {
            tprintf(tinfra::err, "T[%i]: compare_exchange_strong not commited %i (expected=%i, actual=%i)\n", get_thread_string(), desired, expected, protected_var);
            expected = protected_var;
            return false;
        }
    }
};

#define ATOMMOO my_mutex_based_fake_atomic

#endif

static void my_nanosleep(int n)
{
    struct timespec f;
    f.tv_sec = 0;
    f.tv_nsec = n;
    ::nanosleep(&f, 0);
}

#define my_assert(foo) \
    do { \
        if( !(foo) ) { \
            tprintf(tinfra::err, "T[%i]: assertion '%s' failed in %s:%i\n", get_thread_string(), #foo, __FILE__, __LINE__); \
            abort(); \
        } \
    } while(0)

template <typename T>
class atomic_segregated_memory_allocator {
    static_assert(sizeof(T) >= sizeof(int), "T shall be able to store int basic_linked_memory_pool ");

    T* const        buffer_start;
    const size_t    buffer_size;
    ATOMMOO<int> next_free;
    ATOMMOO<int> n_allocated;

public:
    atomic_segregated_memory_allocator(T* ptr, size_t size):
        buffer_start(ptr),
        buffer_size(size),
        next_free(0),
        n_allocated(0)
    {
        this->initialize_storage();
    }

    // C++-like allocator interface
    T* allocate() {
        int allocated_item = next_free.load();

        tprintf(tinfra::err, "T[%i]: allocate first try with allocated_item %i\n", get_thread_string(), allocated_item);
        while( true ) {
            if( allocated_item == -1 ) {
                throw std::bad_alloc();
            }
            int new_next_free = item_next_free_idx(allocated_item);
                // so here is the race
                //  1  (allocated_item AI, new_next_free NNF) pair is "read"
                //  2. (tries to commit, but ... in meantime)
                //  3.   (other thread allocates AI as a race)
                //  3.1  (NNF is allocates by other thread) ...
                //  4.   (other thread deallocates AI and it appears again as NF but now points to NNF2)
                //  5. (commit succedds with NNF because AI is same as in 1)
                //     BUG, NF points at NNF, which is not necessarily allocated
                //     should point at NNF2 (!?) impossible
                //     or TXN this kind of race should be detected and whole TXN shall be retried
            assert(new_next_free != allocated_item);
            if(rand() % 2 ) my_nanosleep(1);
            const bool change_succeded = next_free.compare_exchange_strong(allocated_item, new_next_free);
            if( !change_succeded ) {
                tprintf(tinfra::err, "T[%i]: allocate, retrying with allocated_item %i\n", get_thread_string(), allocated_item);
                continue;
            } else {
                tprintf(tinfra::err, "T[%i]: allocated %i, next_free = %i\n", get_thread_string(), allocated_item, new_next_free);
            }
            break;
        }
        my_assert(_check_allocated(allocated_item));
        ++n_allocated;
        return item_ptr(allocated_item);
    }
    void deallocate(T* p) {
        assert( p >= this->buffer_start && p < this->buffer_start + this->buffer_size);
        //assert( p % sizeof(T) == 0 );

        const int idx = (p - this->buffer_start);
        int       last_next_free = next_free.load();

        tprintf(tinfra::err, "T[%i]: deallocate[%s], first try with last_next_free %i\n", get_thread_string(), idx, last_next_free);
        my_assert( _check_allocated(idx) );

        while( true ) {
            my_assert(last_next_free != idx);
            if(rand() % 2 ) my_nanosleep(1);
            this->item_next_free_idx(idx) = last_next_free;
                // this assertion sometimes fails, so we have some inconsistency
                // in free slot graph !!!
            const bool change_succeded = next_free.compare_exchange_strong(last_next_free, idx);
            if( !change_succeded ) {
                tprintf(tinfra::err, "T[%i]: deallocate[%s], retrying with last_next_free %i\n", get_thread_string(), idx, last_next_free);
                continue;
            } else {
                tprintf(tinfra::err, "T[%i]: deallocate[%i], next_free = %i (linked %i->%i)\n", get_thread_string(), idx, idx, idx, last_next_free);
            }
            break;
        }
        --n_allocated;
    }

    int allocated() const {
        int r = this->buffer_size;
        int i = this->next_free.load();
        while( i != -1 ) {
            i = item_next_free_idx(i);
            r -= 1;
        }
        return r;
        //return this->n_allocated.load(std::memory_order_relaxed);
    }
private:
    bool _check_for_loops() {
        int vector<int>           visited_stream;
        int std::map<int, size_t> when_visited; // (v at k) say, that k is already visited at position v
        int idx = next_free.load();

        while( idx != -1 ) {
            if( when_visited.find(idx) != when_visited.end() ) {
                // we've already seen this value, so WE HAVE LOOP

                tprintf(tinfra::err, "T[%i]: _check_for_loops %i->%i is a loop, whole vector\n", get_thread_string(), last, idx, vector_to_string(visited_stream));
                return false;
            }

            when_visited[idx] = visited_stream.size();
            visited_stream.push_back(idx);
            last = idx;
            idx = item_next_free_idx(idx);
        }
        return true;
    }
    bool _check_allocated(int idx) {
        int i = next_free.load();
        int last = -1;
        while( i != -1 ) {
            if( idx == i ) {
                tprintf(tinfra::err, "T[%i]: _check_allocated(%i) fails, because (%i->%i)\n", get_thread_string(), idx, last, idx);
                _check_for_loops();
                return false;
            }
            last = i;
            i = item_next_free_idx(i);
        }
        return true;
    }

    void initialize_storage()
    {
        for( size_t i = 0; i < this->buffer_size; i++ ) {
            item_next_free_idx(i) = i+1;
        }
        item_next_free_idx(this->buffer_size-1) = -1;
        this->next_free = 0;
    }
    const int& item_next_free_idx(int i) const {
        return * reinterpret_cast<int const*>(this->buffer_start + i);
    }
    int& item_next_free_idx(int i) {
        return * reinterpret_cast<int*>(this->buffer_start + i);
    }
    T*   item_ptr(int i) {
        return this->buffer_start + i;
    }

};

template <typename T, size_t N>
struct static_atomic_segregated_memory_pool {
    typename std::aligned_storage<sizeof(T), alignof(T)>::type buffer[N];
    atomic_segregated_memory_allocator<T> allocator;

public:
    static_atomic_segregated_memory_pool():
        allocator(reinterpret_cast<T*>(buffer), N)
    { }

    // C++ allocator interface
    T* allocate() {
        return this->allocator.allocate();
    }

    void deallocate(T* p) {
        this->allocator.deallocate(p);
    }
    int allocated() const {
        return this->allocator.allocated();
    }
};

#define PPTR(name) ::printf("%s = %p\n", #name, name)

static_atomic_segregated_memory_pool<int, 1024> pool;

void test0()
{
    assert( pool.allocated() == 0);
    int* p = pool.allocate();
    assert( pool.allocated() == 1);
    pool.deallocate(p);
    assert( pool.allocated() == 0);
}

void test1()
{
    const int R = 1024;
    int* ptrs[R];
    assert( pool.allocated() == 0);

    for( int r = 0; r < R; r++ ) {
        ptrs[r] = pool.allocate();
        assert( pool.allocated() == r+1);
    }

    for( int r = 0; r < R; r++ ) {
        pool.deallocate(ptrs[r]);
        assert( pool.allocated() == 1024-(r+1));
    }

    assert( pool.allocated() == 0);
}

void f(int T)
{
    thread_log_idx = thread_count++;
    const int R = 1024;
    const int N = 10;
    int* ptr[N];
    for( int r = 0; r < R; r++ ) {
        //tinfra::tprintf(tinfra::err, "T[%i] before iter %i pool size %i\n", T, r, pool.allocated());
        for( int i = 0; i < N; ++i ) {
            ptr[i] = pool.allocate();
            //tinfra::tprintf(tinfra::err, "T[%i] allocated %i\n", T, ptr[i]);
        }

        for( int i = 0; i < N; ++i ) {
            //tinfra::tprintf(tinfra::err, "T[%i] deallocating %i\n", T, ptr[i]);
            pool.deallocate(ptr[i]);
        }
        //tinfra::tprintf(tinfra::err, "T[%i] before iter %i pool size %i\n", T, r, pool.allocated());
    }
}

void test3()
{
    assert( pool.allocated() == 0);
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f, n);
    }
    for (auto& t : v) {
        t.join();
    }
    tinfra::tprintf(tinfra::err, "T[main] after test pool size %i\n",pool.allocated());
}

int main()
{
    thread_log_idx = thread_count++;
    test0();
    test1();
    test3();
}<|endoftext|>


<commit_before>// ShaderProgram.cpp

#include <GL/glew.h>
#include "ShaderProgram.h"
#include "Application.h"
#include "Frame.h"
#include <wx/glcanvas.h>
#include <wx/file.h>
#include <wx/filename.h>
#include <wx/msgdlg.h>

ShaderProgram::ShaderProgram( void )
{
	program = 0;
	fragmentShader = 0;
	vertexShader = 0;
}

/*virtual*/ ShaderProgram::~ShaderProgram( void )
{
	( void )Unload();
}

bool ShaderProgram::Load( const wxString& shaderName )
{
	bool success = false;

	do
	{
		if( program )
			break;

		if( !MakeShader( shaderName, vertexShader, GL_VERTEX_SHADER ) )
			break;

		if( !MakeShader( shaderName, fragmentShader, GL_FRAGMENT_SHADER ) )
			break;

		program = glCreateProgram();
		if( !program )
			break;

		if( vertexShader )
			glAttachShader( program, vertexShader );

		if( fragmentShader )
			glAttachShader( program, fragmentShader );

		glLinkProgram( program );

		GLint status;
		glGetProgramiv( program, GL_LINK_STATUS, &status );
		if( status == GL_FALSE )
		{
			GLint logLength = 0;
			glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logLength );
			if( logLength > 0 )
			{
				char* infoBuffer = new char[ logLength + 1 ];
				glGetProgramInfoLog( program, logLength, nullptr, infoBuffer );
				wxMessageBox( "Failed to link program " + shaderName + ": " + wxString( infoBuffer ), "Error", wxICON_ERROR | wxCENTRE, wxGetApp().GetFrame() );
				delete[] infoBuffer;
			}

			return false;
		}

		success = true;
	}
	while( false );

	if( !success )
		Unload();

	return success;
}

bool ShaderProgram::MakeShader( const wxString& shaderName, GLuint& shader, GLenum shaderType )
{
	shader = 0;

	wxString shaderExt;
	if( shaderType == GL_VERTEX_SHADER )
		shaderExt = "v";
	else if( shaderType == GL_FRAGMENT_SHADER )
		shaderExt = "f";
	else
		return false;

	wxString shaderFile = wxGetApp().ResolveRelativeResourcePath( "Data/Shaders/" + shaderName + "." + shaderExt + ".glsl" );
	wxFileName fileName( shaderFile );
	if( fileName.Exists() )
	{
		wxFile file( shaderFile );
		wxString shaderCode;
		if( !file.ReadAll( &shaderCode ) )
			return false;

		shader = glCreateShader( shaderType );
		if( !shader )
			return false;

		const char* shaderCodeCStr = ( const char* )shaderCode.c_str();
		GLint shaderCodeLen = shaderCode.Length();
		glShaderSource( shader, 1, &shaderCodeCStr, &shaderCodeLen );
		glCompileShader( shader );

		GLint status;
		glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
		if( status == GL_FALSE )
		{
			char infoBuffer[ 1024 ];
			glGetShaderInfoLog( shader, sizeof( infoBuffer ), nullptr, infoBuffer );
			wxMessageBox( "Failed to compile shader " + shaderName + "." + shaderExt + ": " + wxString( infoBuffer ), "Error", wxICON_ERROR | wxCENTRE, wxGetApp().GetFrame() );
			return false;
		}
	}

	return true;
}

bool ShaderProgram::Unload( void )
{
	if( program )
		glDeleteProgram( program );

	if( vertexShader && glIsShader( vertexShader ) )
		glDeleteShader( vertexShader );

	if( fragmentShader && glIsShader( fragmentShader ) )
		glDeleteShader( fragmentShader );

	program = 0;
	vertexShader = 0;
	fragmentShader = 0;

	return true;
}

bool ShaderProgram::Bind( void )
{
	if( !glIsProgram( program ) )
		return false;

	glUseProgram( program );

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION || error == GL_INVALID_VALUE )
		return false;

	return true;
}

bool ShaderProgram::Unbind( void )
{
	glUseProgram(0);
	return true;
}

bool ShaderProgram::SetUniformVector( const wxString& uniformName, const _3DMath::Vector& vector )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	glUniform3f( location, ( float )vector.x, ( float )vector.y, ( float )vector.z );

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

bool ShaderProgram::SetUniformVectorArray( const wxString& uniformName, const _3DMath::Vector* vectorArray, int vectorCount )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	float* floatArray = new float[ 3 * vectorCount ];
	int j = 0;
	for( int i = 0; i < vectorCount; i++ )
	{
		floatArray[ j++ ] = ( float )vectorArray[i].x;
		floatArray[ j++ ] = ( float )vectorArray[i].y;
		floatArray[ j++ ] = ( float )vectorArray[i].z;
	}

	glUniform3fv( location, vectorCount, floatArray );

	delete[] floatArray;

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

#include <wx/msgdlg.h>

bool ShaderProgram::SetUniformFloat( const wxString& uniformName, double value )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	glUniform1f( location, ( float )value );

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

bool ShaderProgram::SetUniformFloatArray( const wxString& uniformName, const double* valueArray, int valueCount )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	float* floatArray = new float[ valueCount ];
	for( int i = 0; i < valueCount; i++ )
		floatArray[i] = ( float )valueArray[i];

	glUniform1fv( location, valueCount, floatArray );

	delete[] floatArray;

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

bool ShaderProgram::SetUniformInt( const wxString& uniformName, int value )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	glUniform1i( location, value );

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

// ShaderProgram.cpp<commit_msg>oops, this too, clean up<commit_after>// ShaderProgram.cpp

#include <GL/glew.h>
#include "ShaderProgram.h"
#include "Application.h"
#include "Frame.h"
#include <wx/glcanvas.h>
#include <wx/file.h>
#include <wx/filename.h>
#include <wx/msgdlg.h>

ShaderProgram::ShaderProgram( void )
{
	program = 0;
	fragmentShader = 0;
	vertexShader = 0;
}

/*virtual*/ ShaderProgram::~ShaderProgram( void )
{
	( void )Unload();
}

bool ShaderProgram::Load( const wxString& shaderName )
{
	bool success = false;

	do
	{
		if( program )
			break;

		if( !MakeShader( shaderName, vertexShader, GL_VERTEX_SHADER ) )
			break;

		if( !MakeShader( shaderName, fragmentShader, GL_FRAGMENT_SHADER ) )
			break;

		program = glCreateProgram();
		if( !program )
			break;

		if( vertexShader )
			glAttachShader( program, vertexShader );

		if( fragmentShader )
			glAttachShader( program, fragmentShader );

		glLinkProgram( program );

		GLint status;
		glGetProgramiv( program, GL_LINK_STATUS, &status );
		if( status == GL_FALSE )
		{
			GLint logLength = 0;
			glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logLength );
			if( logLength > 0 )
			{
				char* infoBuffer = new char[ logLength + 1 ];
				glGetProgramInfoLog( program, logLength, nullptr, infoBuffer );
				wxMessageBox( "Failed to link program " + shaderName + ": " + wxString( infoBuffer ), "Error", wxICON_ERROR | wxCENTRE, wxGetApp().GetFrame() );
				delete[] infoBuffer;
			}

			return false;
		}

		success = true;
	}
	while( false );

	if( !success )
		Unload();

	return success;
}

bool ShaderProgram::MakeShader( const wxString& shaderName, GLuint& shader, GLenum shaderType )
{
	shader = 0;

	wxString shaderExt;
	if( shaderType == GL_VERTEX_SHADER )
		shaderExt = "v";
	else if( shaderType == GL_FRAGMENT_SHADER )
		shaderExt = "f";
	else
		return false;

	wxString shaderFile = wxGetApp().ResolveRelativeResourcePath( "Data/Shaders/" + shaderName + "." + shaderExt + ".glsl" );
	wxFileName fileName( shaderFile );
	if( fileName.Exists() )
	{
		wxFile file( shaderFile );
		wxString shaderCode;
		if( !file.ReadAll( &shaderCode ) )
			return false;

		shader = glCreateShader( shaderType );
		if( !shader )
			return false;

		const char* shaderCodeCStr = ( const char* )shaderCode.c_str();
		GLint shaderCodeLen = shaderCode.Length();
		glShaderSource( shader, 1, &shaderCodeCStr, &shaderCodeLen );
		glCompileShader( shader );

		GLint status;
		glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
		if( status == GL_FALSE )
		{
			char infoBuffer[ 1024 ];
			glGetShaderInfoLog( shader, sizeof( infoBuffer ), nullptr, infoBuffer );
			wxMessageBox( "Failed to compile shader " + shaderName + "." + shaderExt + ": " + wxString( infoBuffer ), "Error", wxICON_ERROR | wxCENTRE, wxGetApp().GetFrame() );
			return false;
		}
	}

	return true;
}

bool ShaderProgram::Unload( void )
{
	if( program )
		glDeleteProgram( program );

	if( vertexShader && glIsShader( vertexShader ) )
		glDeleteShader( vertexShader );

	if( fragmentShader && glIsShader( fragmentShader ) )
		glDeleteShader( fragmentShader );

	program = 0;
	vertexShader = 0;
	fragmentShader = 0;

	return true;
}

bool ShaderProgram::Bind( void )
{
	if( !glIsProgram( program ) )
		return false;

	glUseProgram( program );

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION || error == GL_INVALID_VALUE )
		return false;

	return true;
}

bool ShaderProgram::Unbind( void )
{
	glUseProgram(0);
	return true;
}

bool ShaderProgram::SetUniformVector( const wxString& uniformName, const _3DMath::Vector& vector )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	glUniform3f( location, ( float )vector.x, ( float )vector.y, ( float )vector.z );

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

bool ShaderProgram::SetUniformVectorArray( const wxString& uniformName, const _3DMath::Vector* vectorArray, int vectorCount )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	float* floatArray = new float[ 3 * vectorCount ];
	int j = 0;
	for( int i = 0; i < vectorCount; i++ )
	{
		floatArray[ j++ ] = ( float )vectorArray[i].x;
		floatArray[ j++ ] = ( float )vectorArray[i].y;
		floatArray[ j++ ] = ( float )vectorArray[i].z;
	}

	glUniform3fv( location, vectorCount, floatArray );

	delete[] floatArray;

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

bool ShaderProgram::SetUniformFloat( const wxString& uniformName, double value )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	glUniform1f( location, ( float )value );

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

bool ShaderProgram::SetUniformFloatArray( const wxString& uniformName, const double* valueArray, int valueCount )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	float* floatArray = new float[ valueCount ];
	for( int i = 0; i < valueCount; i++ )
		floatArray[i] = ( float )valueArray[i];

	glUniform1fv( location, valueCount, floatArray );

	delete[] floatArray;

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

bool ShaderProgram::SetUniformInt( const wxString& uniformName, int value )
{
	GLint location = glGetUniformLocation( program, ( const char* )uniformName.c_str() );
	if( location < 0 )
		return false;

	glUniform1i( location, value );

	GLenum error = glGetError();
	if( error == GL_INVALID_OPERATION )
		return false;

	return true;
}

// ShaderProgram.cpp<|endoftext|>


<commit_before>//=====================================================================//
/*!	@file
	@brief	R8C DS1302 RTC サンプル
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstring>
#include "system.hpp"
#include "clock.hpp"
#include "port.hpp"
#include "common/command.hpp"
#include "common/format.hpp"
#include "common/intr_utils.hpp"
#include "common/port_map.hpp"
#include "common/uart_io.hpp"
#include "common/fifo.hpp"
#include "common/trb_io.hpp"
#include "chip/DS3231.hpp"

namespace {

	typedef device::trb_io<utils::null_task> timer_b;
	timer_b timer_b_;

	typedef utils::fifo<uint8_t, 16> buffer;
	typedef device::uart_io<device::UART0, buffer, buffer> uart;
	uart uart_;

	// I2C ポートの定義クラス
	// P1_B7: SCL
	// P4_B5: SDA
	struct scl_sda {
		void init() const {
			utils::PORT_MAP(utils::port_map::P17::PORT);
			utils::PORT_MAP(utils::port_map::P45::PORT);
			device::POD1.B7 = 1;  // オープン・ドレイン設定
			device::POD4.B5 = 1;  // オープン・ドレイン設定
		}
		void scl_dir(bool b) const { device::PD1.B7 = b; }  // SCL 方向 (0:in, 1:out)
		void scl_out(bool b) const { device::P1.B7 = b; }   // SCL 出力
		bool scl_inp() const { return device::P1.B7(); }    // SCL 入力
		void sda_dir(bool b) const { device::PD4.B5 = b; }  // SDA 方向 (0:in, 1:out)
		void sda_out(bool b) const { device::P4.B5 = b; }   // SDA 出力
		bool sda_inp() const { return device::P4.B5(); }    // SDA 入力
	};

	typedef device::iica_io<scl_sda> iica;
	iica i2c_;
	chip::DS3231<iica> rtc_(i2c_);

	utils::command<64> command_;
}

extern "C" {
	void sci_putch(char ch) {
		uart_.putch(ch);
	}

	char sci_getch(void) {
		return uart_.getch();
	}

	uint16_t sci_length() {
		return uart_.length();
	}

	void sci_puts(const char* str) {
		uart_.puts(str);
	}
}

extern "C" {
	const void* variable_vectors_[] __attribute__ ((section (".vvec"))) = {
		reinterpret_cast<void*>(brk_inst_),		nullptr,	// (0)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (1) flash_ready
		reinterpret_cast<void*>(null_task_),	nullptr,	// (2)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (3)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (4) コンパレーターB1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (5) コンパレーターB3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (6)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (7) タイマＲＣ

		reinterpret_cast<void*>(null_task_),	nullptr,	// (8)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (9)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (10)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (11)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (12)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (13) キー入力
		reinterpret_cast<void*>(null_task_),	nullptr,	// (14) A/D 変換
		reinterpret_cast<void*>(null_task_),	nullptr,	// (15)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (16)
		reinterpret_cast<void*>(uart_.isend),	nullptr,	// (17) UART0 送信
		reinterpret_cast<void*>(uart_.irecv),	nullptr,	// (18) UART0 受信
		reinterpret_cast<void*>(null_task_),	nullptr,	// (19)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (20)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (21) /INT2
		reinterpret_cast<void*>(null_task_),	nullptr,	// (22) タイマＲＪ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (23) 周期タイマ

		reinterpret_cast<void*>(timer_b_.itask),nullptr,	// (24) タイマＲＢ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (25) /INT1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (26) /INT3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (27)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (28)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (29) /INT0
		reinterpret_cast<void*>(null_task_),	nullptr,	// (30)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (31)
	};
}

namespace {
	time_t get_time_() {
		time_t t = 0;
		if(!rtc_.get_time(t)) {
			sci_puts("Stall RTC read...\n");
		}
		return t;
	}

	const char* wday_[] = {
		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
	};

	const char* mon_[] = {
		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
	};

	void disp_time_(time_t t) {
		struct tm *m = gmtime(&t);
		utils::format("%s %s %d %02d:%02d:%02d  %4d\n")
			% wday_[m->tm_wday]
			% mon_[m->tm_mon]
			% static_cast<uint32_t>(m->tm_mday)
			% static_cast<uint32_t>(m->tm_hour)
			% static_cast<uint32_t>(m->tm_min)
			% static_cast<uint32_t>(m->tm_sec)
			% static_cast<uint32_t>(m->tm_year + 1900);
	}

	const char* get_dec_(const char* p, char tmch, int& value) {
		int v = 0;
		char ch;
		while((ch = *p) != 0) {
			++p;
			if(ch == tmch) {
				break;
			} else if(ch >= '0' && ch <= '9') {
				v *= 10;
				v += ch - '0';
			} else {
				return nullptr;
			}
		}
		value = v;
		return p;
	}

	void set_time_date_()
	{
		time_t t = get_time_();
		if(t == 0) return;

		struct tm *m = gmtime(&t);
		bool err = false;
		if(command_.get_words() == 3) {
			char buff[12];
			if(command_.get_word(1, sizeof(buff), buff)) {
				const char* p = buff;
				int vs[3];
				uint8_t i;
				for(i = 0; i < 3; ++i) {
					p = get_dec_(p, '/', vs[i]);
					if(p == nullptr) {
						break;
					}
				}
				if(p != nullptr && p[0] == 0 && i == 3) {
					if(vs[0] >= 1900 && vs[0] < 2100) m->tm_year = vs[0] - 1900;
					if(vs[1] >= 1 && vs[1] <= 12) m->tm_mon = vs[1] - 1;
					if(vs[2] >= 1 && vs[2] <= 31) m->tm_mday = vs[2];
				} else {
					err = true;
				}
			}

			if(command_.get_word(2, sizeof(buff), buff)) {
				const char* p = buff;
				int vs[3];
				uint8_t i;
				for(i = 0; i < 3; ++i) {
					p = get_dec_(p, ':', vs[i]);
					if(p == nullptr) {
						break;
					}
				}
				if(p != nullptr && p[0] == 0 && (i == 2 || i == 3)) {
					if(vs[0] >= 0 && vs[0] < 24) m->tm_hour = vs[0];
					if(vs[1] >= 0 && vs[1] < 60) m->tm_min = vs[1];
					if(i == 3 && vs[2] >= 0 && vs[2] < 60) m->tm_sec = vs[2];
					else m->tm_sec = 0;
				} else {
					err = true;
				}
			}
		}

		if(err) {
			sci_puts("Can't analize Time/Date input.\n");
			return;
		}

		time_t tt = mktime(m);
		if(!rtc_.set_time(tt)) {
			sci_puts("Stall RTC write...\n");
		}
	}
}

 __attribute__ ((section (".exttext")))
int main(int argc, char *argv[])
{
	using namespace device;

// クロック関係レジスタ・プロテクト解除
	PRCR.PRC0 = 1;

// 高速オンチップオシレーターへ切り替え(20MHz)
// ※ F_CLK を設定する事（Makefile内）
	OCOCR.HOCOE = 1;
	utils::delay::micro_second(1);  // >=30us(125KHz)
	SCKCR.HSCKSEL = 1;
	CKSTPR.SCKSEL = 1;

	// タイマーＢ初期化
	{
		uint8_t ir_level = 2;
		timer_b_.start_timer(60, ir_level);
	}

	// UART の設定 (P1_4: TXD0[out], P1_5: RXD0[in])
	// ※シリアルライターでは、RXD 端子は、P1_6 となっているので注意！
	{
		utils::PORT_MAP(utils::port_map::P14::TXD0);
		utils::PORT_MAP(utils::port_map::P15::RXD0);
		uint8_t ir_level = 1;
		uart_.start(57600, ir_level);
	}

	// I2C クラスの初期化
	{
		i2c_.start(iica::speed::fast);
	}

	// RTC を開始
	{
		rtc_.start();
	}

	sci_puts("Start R8C RTC monitor\n");
	command_.set_prompt("# ");

	// LED シグナル用ポートを出力
	PD1.B0 = 1;

	uint8_t cnt = 0;
	while(1) {
		timer_b_.sync();

		if(cnt >= 20) {
			cnt = 0;
		}
		if(cnt < 10) P1.B0 = 1;
		else P1.B0 = 0;
		++cnt;

		// コマンド入力と、コマンド解析
		if(command_.service()) {
			uint8_t cmdn = command_.get_words();
			if(cmdn >= 1) {
				if(command_.cmp_word(0, "date")) {
					if(cmdn == 1) {
						time_t t = get_time_();
						if(t != 0) {
							disp_time_(t);
						}
					} else {
						set_time_date_();
					}
				} else if(command_.cmp_word(0, "help")) {
					sci_puts("date\n");
					sci_puts("date yyyy/mm/dd hh:mm[:ss]\n");
				} else {
					char buff[12];
					if(command_.get_word(0, sizeof(buff), buff)) {
						sci_puts("Command error: ");
						sci_puts(buff);
						sci_putch('\n');
					}
				}
			}
		}
	}
}
<commit_msg>update comment<commit_after>//=====================================================================//
/*!	@file
	@brief	R8C DS3231 RTC サンプル
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstring>
#include "system.hpp"
#include "clock.hpp"
#include "port.hpp"
#include "common/command.hpp"
#include "common/format.hpp"
#include "common/intr_utils.hpp"
#include "common/port_map.hpp"
#include "common/uart_io.hpp"
#include "common/fifo.hpp"
#include "common/trb_io.hpp"
#include "chip/DS3231.hpp"

namespace {

	typedef device::trb_io<utils::null_task> timer_b;
	timer_b timer_b_;

	typedef utils::fifo<uint8_t, 16> buffer;
	typedef device::uart_io<device::UART0, buffer, buffer> uart;
	uart uart_;

	// I2C ポートの定義クラス
	// P1_B7: SCL
	// P4_B5: SDA
	struct scl_sda {
		void init() const {
			utils::PORT_MAP(utils::port_map::P17::PORT);
			utils::PORT_MAP(utils::port_map::P45::PORT);
			device::POD1.B7 = 1;  // オープン・ドレイン設定
			device::POD4.B5 = 1;  // オープン・ドレイン設定
		}
		void scl_dir(bool b) const { device::PD1.B7 = b; }  // SCL 方向 (0:in, 1:out)
		void scl_out(bool b) const { device::P1.B7 = b; }   // SCL 出力
		bool scl_inp() const { return device::P1.B7(); }    // SCL 入力
		void sda_dir(bool b) const { device::PD4.B5 = b; }  // SDA 方向 (0:in, 1:out)
		void sda_out(bool b) const { device::P4.B5 = b; }   // SDA 出力
		bool sda_inp() const { return device::P4.B5(); }    // SDA 入力
	};

	typedef device::iica_io<scl_sda> iica;
	iica i2c_;
	chip::DS3231<iica> rtc_(i2c_);

	utils::command<64> command_;
}

extern "C" {
	void sci_putch(char ch) {
		uart_.putch(ch);
	}

	char sci_getch(void) {
		return uart_.getch();
	}

	uint16_t sci_length() {
		return uart_.length();
	}

	void sci_puts(const char* str) {
		uart_.puts(str);
	}
}

extern "C" {
	const void* variable_vectors_[] __attribute__ ((section (".vvec"))) = {
		reinterpret_cast<void*>(brk_inst_),		nullptr,	// (0)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (1) flash_ready
		reinterpret_cast<void*>(null_task_),	nullptr,	// (2)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (3)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (4) コンパレーターB1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (5) コンパレーターB3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (6)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (7) タイマＲＣ

		reinterpret_cast<void*>(null_task_),	nullptr,	// (8)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (9)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (10)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (11)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (12)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (13) キー入力
		reinterpret_cast<void*>(null_task_),	nullptr,	// (14) A/D 変換
		reinterpret_cast<void*>(null_task_),	nullptr,	// (15)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (16)
		reinterpret_cast<void*>(uart_.isend),	nullptr,	// (17) UART0 送信
		reinterpret_cast<void*>(uart_.irecv),	nullptr,	// (18) UART0 受信
		reinterpret_cast<void*>(null_task_),	nullptr,	// (19)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (20)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (21) /INT2
		reinterpret_cast<void*>(null_task_),	nullptr,	// (22) タイマＲＪ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (23) 周期タイマ

		reinterpret_cast<void*>(timer_b_.itask),nullptr,	// (24) タイマＲＢ２
		reinterpret_cast<void*>(null_task_),	nullptr,	// (25) /INT1
		reinterpret_cast<void*>(null_task_),	nullptr,	// (26) /INT3
		reinterpret_cast<void*>(null_task_),	nullptr,	// (27)

		reinterpret_cast<void*>(null_task_),	nullptr,	// (28)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (29) /INT0
		reinterpret_cast<void*>(null_task_),	nullptr,	// (30)
		reinterpret_cast<void*>(null_task_),	nullptr,	// (31)
	};
}

namespace {
	time_t get_time_() {
		time_t t = 0;
		if(!rtc_.get_time(t)) {
			sci_puts("Stall RTC read...\n");
		}
		return t;
	}

	const char* wday_[] = {
		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
	};

	const char* mon_[] = {
		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
	};

	void disp_time_(time_t t) {
		struct tm *m = gmtime(&t);
		utils::format("%s %s %d %02d:%02d:%02d  %4d\n")
			% wday_[m->tm_wday]
			% mon_[m->tm_mon]
			% static_cast<uint32_t>(m->tm_mday)
			% static_cast<uint32_t>(m->tm_hour)
			% static_cast<uint32_t>(m->tm_min)
			% static_cast<uint32_t>(m->tm_sec)
			% static_cast<uint32_t>(m->tm_year + 1900);
	}

	const char* get_dec_(const char* p, char tmch, int& value) {
		int v = 0;
		char ch;
		while((ch = *p) != 0) {
			++p;
			if(ch == tmch) {
				break;
			} else if(ch >= '0' && ch <= '9') {
				v *= 10;
				v += ch - '0';
			} else {
				return nullptr;
			}
		}
		value = v;
		return p;
	}

	void set_time_date_()
	{
		time_t t = get_time_();
		if(t == 0) return;

		struct tm *m = gmtime(&t);
		bool err = false;
		if(command_.get_words() == 3) {
			char buff[12];
			if(command_.get_word(1, sizeof(buff), buff)) {
				const char* p = buff;
				int vs[3];
				uint8_t i;
				for(i = 0; i < 3; ++i) {
					p = get_dec_(p, '/', vs[i]);
					if(p == nullptr) {
						break;
					}
				}
				if(p != nullptr && p[0] == 0 && i == 3) {
					if(vs[0] >= 1900 && vs[0] < 2100) m->tm_year = vs[0] - 1900;
					if(vs[1] >= 1 && vs[1] <= 12) m->tm_mon = vs[1] - 1;
					if(vs[2] >= 1 && vs[2] <= 31) m->tm_mday = vs[2];
				} else {
					err = true;
				}
			}

			if(command_.get_word(2, sizeof(buff), buff)) {
				const char* p = buff;
				int vs[3];
				uint8_t i;
				for(i = 0; i < 3; ++i) {
					p = get_dec_(p, ':', vs[i]);
					if(p == nullptr) {
						break;
					}
				}
				if(p != nullptr && p[0] == 0 && (i == 2 || i == 3)) {
					if(vs[0] >= 0 && vs[0] < 24) m->tm_hour = vs[0];
					if(vs[1] >= 0 && vs[1] < 60) m->tm_min = vs[1];
					if(i == 3 && vs[2] >= 0 && vs[2] < 60) m->tm_sec = vs[2];
					else m->tm_sec = 0;
				} else {
					err = true;
				}
			}
		}

		if(err) {
			sci_puts("Can't analize Time/Date input.\n");
			return;
		}

		time_t tt = mktime(m);
		if(!rtc_.set_time(tt)) {
			sci_puts("Stall RTC write...\n");
		}
	}
}

 __attribute__ ((section (".exttext")))
int main(int argc, char *argv[])
{
	using namespace device;

// クロック関係レジスタ・プロテクト解除
	PRCR.PRC0 = 1;

// 高速オンチップオシレーターへ切り替え(20MHz)
// ※ F_CLK を設定する事（Makefile内）
	OCOCR.HOCOE = 1;
	utils::delay::micro_second(1);  // >=30us(125KHz)
	SCKCR.HSCKSEL = 1;
	CKSTPR.SCKSEL = 1;

	// タイマーＢ初期化
	{
		uint8_t ir_level = 2;
		timer_b_.start_timer(60, ir_level);
	}

	// UART の設定 (P1_4: TXD0[out], P1_5: RXD0[in])
	// ※シリアルライターでは、RXD 端子は、P1_6 となっているので注意！
	{
		utils::PORT_MAP(utils::port_map::P14::TXD0);
		utils::PORT_MAP(utils::port_map::P15::RXD0);
		uint8_t ir_level = 1;
		uart_.start(57600, ir_level);
	}

	// I2C クラスの初期化
	{
		i2c_.start(iica::speed::fast);
	}

	// RTC を開始
	{
		rtc_.start();
	}

	sci_puts("Start R8C RTC monitor\n");
	command_.set_prompt("# ");

	// LED シグナル用ポートを出力
	PD1.B0 = 1;

	uint8_t cnt = 0;
	while(1) {
		timer_b_.sync();

		if(cnt >= 20) {
			cnt = 0;
		}
		if(cnt < 10) P1.B0 = 1;
		else P1.B0 = 0;
		++cnt;

		// コマンド入力と、コマンド解析
		if(command_.service()) {
			uint8_t cmdn = command_.get_words();
			if(cmdn >= 1) {
				if(command_.cmp_word(0, "date")) {
					if(cmdn == 1) {
						time_t t = get_time_();
						if(t != 0) {
							disp_time_(t);
						}
					} else {
						set_time_date_();
					}
				} else if(command_.cmp_word(0, "help")) {
					sci_puts("date\n");
					sci_puts("date yyyy/mm/dd hh:mm[:ss]\n");
				} else {
					char buff[12];
					if(command_.get_word(0, sizeof(buff), buff)) {
						sci_puts("Command error: ");
						sci_puts(buff);
						sci_putch('\n');
					}
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>#include "Runtime/Character/CCharacterInfo.hpp"

namespace urde {

CCharacterInfo::CParticleResData::CParticleResData(CInputStream& in, u16 tableCount) {
  u32 partCount = in.readUint32Big();
  x0_part.reserve(partCount);
  for (u32 i = 0; i < partCount; ++i)
    x0_part.push_back(in.readUint32Big());

  u32 swhcCount = in.readUint32Big();
  x10_swhc.reserve(swhcCount);
  for (u32 i = 0; i < swhcCount; ++i)
    x10_swhc.push_back(in.readUint32Big());

  u32 unkCount = in.readUint32Big();
  x20_elsc.reserve(unkCount);
  for (u32 i = 0; i < unkCount; ++i)
    x20_elsc.push_back(in.readUint32Big());

  if (tableCount > 5) {
    u32 elscCount = in.readUint32Big();
    x30_elsc.reserve(elscCount);
    for (u32 i = 0; i < elscCount; ++i)
      x30_elsc.push_back(in.readUint32Big());
  }
}

static std::vector<std::pair<s32, std::pair<std::string, std::string>>> MakeAnimInfoVector(CInputStream& in) {
  std::vector<std::pair<s32, std::pair<std::string, std::string>>> ret;
  u32 animInfoCount = in.readUint32Big();
  ret.reserve(animInfoCount);
  for (u32 i = 0; i < animInfoCount; ++i) {
    s32 idx = in.readInt32Big();
    std::string a = in.readString();
    std::string b = in.readString();
    ret.emplace_back(idx, std::make_pair(a, b));
  }
  return ret;
}

CCharacterInfo::CCharacterInfo(CInputStream& in)
: x0_tableCount(in.readUint16Big())
, x4_name(in.readString())
, x14_cmdl(in.readUint32Big())
, x18_cskr(in.readUint32Big())
, x1c_cinf(in.readUint32Big())
, x20_animInfo(MakeAnimInfoVector(in))
, x30_pasDatabase(in)
, x44_partRes(in, x0_tableCount)
, x84_unk(in.readUint32Big()) {
  if (x0_tableCount > 1) {
    u32 aabbCount = in.readUint32Big();
    x88_aabbs.reserve(aabbCount);
    for (u32 i = 0; i < aabbCount; ++i) {
      std::string name = in.readString();
      x88_aabbs.emplace_back(name, zeus::CAABox());
      x88_aabbs.back().second.readBoundingBoxBig(in);
    }
  }

  if (x0_tableCount > 2) {
    u32 effectCount = in.readUint32Big();
    x98_effects.reserve(effectCount);
    for (u32 i = 0; i < effectCount; ++i) {
      std::string name = in.readString();
      x98_effects.emplace_back(name, std::vector<CEffectComponent>());
      std::vector<CEffectComponent>& comps = x98_effects.back().second;
      u32 compCount = in.readUint32Big();
      comps.reserve(compCount);
      for (u32 j = 0; j < compCount; ++j)
        comps.emplace_back(in);
    }
  }

  if (x0_tableCount > 3) {
    xa8_cmdlOverlay = in.readUint32Big();
    xac_cskrOverlay = in.readUint32Big();
  }

  if (x0_tableCount > 4) {
    u32 aidxCount = in.readUint32Big();
    xb0_animIdxs.reserve(aidxCount);
    for (u32 i = 0; i < aidxCount; ++i)
      xb0_animIdxs.push_back(in.readInt32Big());
  }
}

const s32 CCharacterInfo::GetAnimationIndex(std::string_view name) const {
  for (const auto& pair : x20_animInfo) {
    if (pair.second.second == name)
      return pair.first;
  }

  return -1;
}

} // namespace urde
<commit_msg>CCharacterInfo: Make use of emplace_back() where applicable<commit_after>#include "Runtime/Character/CCharacterInfo.hpp"

namespace urde {

CCharacterInfo::CParticleResData::CParticleResData(CInputStream& in, u16 tableCount) {
  const u32 partCount = in.readUint32Big();
  x0_part.reserve(partCount);
  for (u32 i = 0; i < partCount; ++i) {
    x0_part.emplace_back(in.readUint32Big());
  }

  const u32 swhcCount = in.readUint32Big();
  x10_swhc.reserve(swhcCount);
  for (u32 i = 0; i < swhcCount; ++i) {
    x10_swhc.emplace_back(in.readUint32Big());
  }

  const u32 unkCount = in.readUint32Big();
  x20_elsc.reserve(unkCount);
  for (u32 i = 0; i < unkCount; ++i) {
    x20_elsc.emplace_back(in.readUint32Big());
  }

  if (tableCount > 5) {
    const u32 elscCount = in.readUint32Big();
    x30_elsc.reserve(elscCount);
    for (u32 i = 0; i < elscCount; ++i) {
      x30_elsc.emplace_back(in.readUint32Big());
    }
  }
}

static std::vector<std::pair<s32, std::pair<std::string, std::string>>> MakeAnimInfoVector(CInputStream& in) {
  std::vector<std::pair<s32, std::pair<std::string, std::string>>> ret;
  u32 animInfoCount = in.readUint32Big();
  ret.reserve(animInfoCount);
  for (u32 i = 0; i < animInfoCount; ++i) {
    s32 idx = in.readInt32Big();
    std::string a = in.readString();
    std::string b = in.readString();
    ret.emplace_back(idx, std::make_pair(a, b));
  }
  return ret;
}

CCharacterInfo::CCharacterInfo(CInputStream& in)
: x0_tableCount(in.readUint16Big())
, x4_name(in.readString())
, x14_cmdl(in.readUint32Big())
, x18_cskr(in.readUint32Big())
, x1c_cinf(in.readUint32Big())
, x20_animInfo(MakeAnimInfoVector(in))
, x30_pasDatabase(in)
, x44_partRes(in, x0_tableCount)
, x84_unk(in.readUint32Big()) {
  if (x0_tableCount > 1) {
    u32 aabbCount = in.readUint32Big();
    x88_aabbs.reserve(aabbCount);
    for (u32 i = 0; i < aabbCount; ++i) {
      std::string name = in.readString();
      x88_aabbs.emplace_back(name, zeus::CAABox());
      x88_aabbs.back().second.readBoundingBoxBig(in);
    }
  }

  if (x0_tableCount > 2) {
    u32 effectCount = in.readUint32Big();
    x98_effects.reserve(effectCount);
    for (u32 i = 0; i < effectCount; ++i) {
      std::string name = in.readString();
      x98_effects.emplace_back(name, std::vector<CEffectComponent>());
      std::vector<CEffectComponent>& comps = x98_effects.back().second;
      u32 compCount = in.readUint32Big();
      comps.reserve(compCount);
      for (u32 j = 0; j < compCount; ++j)
        comps.emplace_back(in);
    }
  }

  if (x0_tableCount > 3) {
    xa8_cmdlOverlay = in.readUint32Big();
    xac_cskrOverlay = in.readUint32Big();
  }

  if (x0_tableCount > 4) {
    u32 aidxCount = in.readUint32Big();
    xb0_animIdxs.reserve(aidxCount);
    for (u32 i = 0; i < aidxCount; ++i)
      xb0_animIdxs.push_back(in.readInt32Big());
  }
}

const s32 CCharacterInfo::GetAnimationIndex(std::string_view name) const {
  for (const auto& pair : x20_animInfo) {
    if (pair.second.second == name)
      return pair.first;
  }

  return -1;
}

} // namespace urde
<|endoftext|>


<commit_before>#include "cpprx/rx.hpp"
namespace rx=rxcpp;

#include "catch.hpp"

SCENARIO("select_many completes", "[select_many][map][operators]"){
    GIVEN("two cold observables. one of ints. one of strings."){
        auto scheduler = std::make_shared<rx::TestScheduler>();
        typedef rx::TestScheduler::Messages<int> m;
        typedef rx::TestScheduler::Messages<std::string> ms;

        long invoked = 0;

        auto xs = scheduler->CreateColdObservable(
            []() {
                m::RecordedT messages[] = {
                    m::OnNext(100, 4),
                    m::OnNext(200, 2),
                    m::OnNext(300, 3),
                    m::OnNext(400, 1),
                    m::OnCompleted(500)
                };
                return m::ToVector(messages);
            }()
        );

        auto ys = scheduler->CreateColdObservable(
            []() {
                ms::RecordedT messages[] = {
                    ms::OnNext(50, "foo"),
                    ms::OnNext(100, "bar"),
                    ms::OnNext(150, "baz"),
                    ms::OnNext(200, "qux"),
                    ms::OnCompleted(250)
                };
                return ms::ToVector(messages);
            }()
        );

        WHEN("each int is mapped to the strings"){

            auto res = scheduler->Start<std::string>(
                [&]() {
                    return observable(from(xs)
                        .select_many([&](int){return ys;}));
                }
            );

            THEN("the output contains strings repeated for each int"){
                ms::RecordedT items[] = {
                    ms::OnNext(350, "foo"),
                    ms::OnNext(400, "bar"),
                    ms::OnNext(450, "foo"),
                    ms::OnNext(450, "baz"),
                    ms::OnNext(500, "bar"),
                    ms::OnNext(500, "qux"),
                    ms::OnNext(550, "baz"),
                    ms::OnNext(550, "foo"),
                    ms::OnNext(600, "bar"),
                    ms::OnNext(600, "qux"),
                    ms::OnNext(650, "baz"),
                    ms::OnNext(650, "foo"),
                    ms::OnNext(700, "qux"),
                    ms::OnNext(700, "bar"),
                    ms::OnNext(750, "baz"),
                    ms::OnNext(800, "qux"),
                    ms::OnCompleted(850)
                };
                auto required = ms::ToVector(items);
                auto actual = res->Messages();
                REQUIRE(required == actual);
            }

            THEN("there was one subscription and one unsubscription to the ints"){
                rx::Subscription items[] = {
                    m::Subscribe(200, 700)
                };
                auto required = m::ToVector(items);
                auto actual = xs->Subscriptions();
                REQUIRE(required == actual);
            }

            THEN("there were four subscription and unsubscription to the strings"){
                rx::Subscription items[] = {
                    ms::Subscribe(300, 550),
                    ms::Subscribe(400, 650),
                    ms::Subscribe(500, 750),
                    ms::Subscribe(600, 850)
                };
                auto required = m::ToVector(items);
                auto actual = ys->Subscriptions();
                REQUIRE(required == actual);
            }
        }
    }
}

SCENARIO("select_many source never ends", "[select_many][map][operators]"){
    GIVEN("two cold observables. one of ints. one of strings."){
        auto scheduler = std::make_shared<rx::TestScheduler>();
        typedef rx::TestScheduler::Messages<int> m;
        typedef rx::TestScheduler::Messages<std::string> ms;

        long invoked = 0;

        auto xs = scheduler->CreateColdObservable(
            []() {
                m::RecordedT messages[] = {
                    m::OnNext(100, 4),
                    m::OnNext(200, 2),
                    m::OnNext(300, 3),
                    m::OnNext(400, 1),
                    m::OnNext(500, 5),
                    m::OnNext(700, 0)
                };
                return m::ToVector(messages);
            }()
        );

        auto ys = scheduler->CreateColdObservable(
            []() {
                ms::RecordedT messages[] = {
                    ms::OnNext(50, "foo"),
                    ms::OnNext(100, "bar"),
                    ms::OnNext(150, "baz"),
                    ms::OnNext(200, "qux"),
                    ms::OnCompleted(250)
                };
                return ms::ToVector(messages);
            }()
        );

        WHEN("each int is mapped to the strings"){

            auto res = scheduler->Start<std::string>(
                [&]() {
                    return observable(from(xs)
                        .select_many([&](int){return ys;}));
                }
            );

            THEN("the output contains strings repeated for each int"){
                ms::RecordedT items[] = {
                    ms::OnNext(350, "foo"),
                    ms::OnNext(400, "bar"),
                    ms::OnNext(450, "baz"),
                    ms::OnNext(450, "foo"),
                    ms::OnNext(500, "bar"),
                    ms::OnNext(500, "qux"),
                    ms::OnNext(550, "baz"),
                    ms::OnNext(550, "foo"),
                    ms::OnNext(600, "qux"),
                    ms::OnNext(600, "bar"),
                    ms::OnNext(650, "baz"),
                    ms::OnNext(650, "foo"),
                    ms::OnNext(700, "qux"),
                    ms::OnNext(700, "bar"),
                    ms::OnNext(750, "baz"),
                    ms::OnNext(750, "foo"),
                    ms::OnNext(800, "qux"),
                    ms::OnNext(800, "bar"),
                    ms::OnNext(850, "baz"),
                    ms::OnNext(900, "qux"),
                    ms::OnNext(950, "foo"),
                    ms::OnNext(1000, "bar")
                };
                auto required = ms::ToVector(items);
                auto actual = res->Messages();
                REQUIRE(required == actual);
            }

            THEN("there was one subscription and one unsubscription to the ints"){
                rx::Subscription items[] = {
                    m::Subscribe(200, 1000)
                };
                auto required = m::ToVector(items);
                auto actual = xs->Subscriptions();
                REQUIRE(required == actual);
            }

            THEN("there were four subscription and unsubscription to the strings"){
                rx::Subscription items[] = {
                    ms::Subscribe(300, 550),
                    ms::Subscribe(400, 650),
                    ms::Subscribe(500, 750),
                    ms::Subscribe(600, 850),
                    ms::Subscribe(700, 950),
                    ms::Subscribe(900, 1000)
                };
                auto required = m::ToVector(items);
                auto actual = ys->Subscriptions();
                REQUIRE(required == actual);
            }
        }
    }
}

SCENARIO("select_many inner error", "[select_many][map][operators]"){
    GIVEN("two cold observables. one of ints. one of strings."){
        auto scheduler = std::make_shared<rx::TestScheduler>();
        typedef rx::TestScheduler::Messages<int> m;
        typedef rx::TestScheduler::Messages<std::string> ms;

        long invoked = 0;

        auto xs = scheduler->CreateColdObservable(
            []() {
                m::RecordedT messages[] = {
                    m::OnNext(100, 4),
                    m::OnNext(200, 2),
                    m::OnNext(300, 3),
                    m::OnNext(400, 1),
                    m::OnCompleted(500)
                };
                return m::ToVector(messages);
            }()
        );

        auto ys = scheduler->CreateColdObservable(
            []() {
                ms::RecordedT messages[] = {
                    ms::OnNext(55, "foo"),
                    ms::OnNext(104, "bar"),
                    ms::OnNext(153, "baz"),
                    ms::OnNext(202, "qux"),
                    ms::OnError(301, std::exception())
                };
                return ms::ToVector(messages);
            }()
        );

        WHEN("each int is mapped to the strings"){

            auto res = scheduler->Start<std::string>(
                [&]() {
                    return observable(from(xs)
                        .select_many([&](int){return ys;}));
                }
            );

            THEN("the output contains strings repeated for each int"){
                ms::RecordedT items[] = {
                    ms::OnNext(355, "foo"),
                    ms::OnNext(404, "bar"),
                    ms::OnNext(453, "baz"),
                    ms::OnNext(455, "foo"),
                    ms::OnNext(502, "qux"),
                    ms::OnNext(504, "bar"),
                    ms::OnNext(553, "baz"),
                    ms::OnNext(555, "foo"),
                    ms::OnError(601, std::exception())
                };
                auto required = ms::ToVector(items);
                auto actual = res->Messages();
                REQUIRE(required == actual);
            }

            THEN("there was one subscription and one unsubscription to the ints"){
                rx::Subscription items[] = {
                    m::Subscribe(200, 601)
                };
                auto required = m::ToVector(items);
                auto actual = xs->Subscriptions();
                REQUIRE(required == actual);
            }

            THEN("there were four subscription and unsubscription to the strings"){
                rx::Subscription items[] = {
                    ms::Subscribe(300, 601),
                    ms::Subscribe(400, 601),
                    ms::Subscribe(500, 601),
                    ms::Subscribe(600, 601)
                };
                auto required = ms::ToVector(items);
                auto actual = ys->Subscriptions();
                REQUIRE(required == actual);
            }
        }
    }
}
<commit_msg>avoid more overlapping events<commit_after>#include "cpprx/rx.hpp"
namespace rx=rxcpp;

#include "catch.hpp"

SCENARIO("select_many completes", "[select_many][map][operators]"){
    GIVEN("two cold observables. one of ints. one of strings."){
        auto scheduler = std::make_shared<rx::TestScheduler>();
        typedef rx::TestScheduler::Messages<int> m;
        typedef rx::TestScheduler::Messages<std::string> ms;

        long invoked = 0;

        auto xs = scheduler->CreateColdObservable(
            []() {
                m::RecordedT messages[] = {
                    m::OnNext(100, 4),
                    m::OnNext(200, 2),
                    m::OnNext(300, 3),
                    m::OnNext(400, 1),
                    m::OnCompleted(500)
                };
                return m::ToVector(messages);
            }()
        );

        auto ys = scheduler->CreateColdObservable(
            []() {
                ms::RecordedT messages[] = {
                    ms::OnNext(50, "foo"),
                    ms::OnNext(100, "bar"),
                    ms::OnNext(150, "baz"),
                    ms::OnNext(200, "qux"),
                    ms::OnCompleted(250)
                };
                return ms::ToVector(messages);
            }()
        );

        WHEN("each int is mapped to the strings"){

            auto res = scheduler->Start<std::string>(
                [&]() {
                    return observable(from(xs)
                        .select_many([&](int){return ys;}));
                }
            );

            THEN("the output contains strings repeated for each int"){
                ms::RecordedT items[] = {
                    ms::OnNext(350, "foo"),
                    ms::OnNext(400, "bar"),
                    ms::OnNext(450, "foo"),
                    ms::OnNext(450, "baz"),
                    ms::OnNext(500, "bar"),
                    ms::OnNext(500, "qux"),
                    ms::OnNext(550, "baz"),
                    ms::OnNext(550, "foo"),
                    ms::OnNext(600, "bar"),
                    ms::OnNext(600, "qux"),
                    ms::OnNext(650, "baz"),
                    ms::OnNext(650, "foo"),
                    ms::OnNext(700, "qux"),
                    ms::OnNext(700, "bar"),
                    ms::OnNext(750, "baz"),
                    ms::OnNext(800, "qux"),
                    ms::OnCompleted(850)
                };
                auto required = ms::ToVector(items);
                auto actual = res->Messages();
                REQUIRE(required == actual);
            }

            THEN("there was one subscription and one unsubscription to the ints"){
                rx::Subscription items[] = {
                    m::Subscribe(200, 700)
                };
                auto required = m::ToVector(items);
                auto actual = xs->Subscriptions();
                REQUIRE(required == actual);
            }

            THEN("there were four subscription and unsubscription to the strings"){
                rx::Subscription items[] = {
                    ms::Subscribe(300, 550),
                    ms::Subscribe(400, 650),
                    ms::Subscribe(500, 750),
                    ms::Subscribe(600, 850)
                };
                auto required = m::ToVector(items);
                auto actual = ys->Subscriptions();
                REQUIRE(required == actual);
            }
        }
    }
}

SCENARIO("select_many source never ends", "[select_many][map][operators]"){
    GIVEN("two cold observables. one of ints. one of strings."){
        auto scheduler = std::make_shared<rx::TestScheduler>();
        typedef rx::TestScheduler::Messages<int> m;
        typedef rx::TestScheduler::Messages<std::string> ms;

        long invoked = 0;

        auto xs = scheduler->CreateColdObservable(
            []() {
                m::RecordedT messages[] = {
                    m::OnNext(100, 4),
                    m::OnNext(200, 2),
                    m::OnNext(300, 3),
                    m::OnNext(400, 1),
                    m::OnNext(500, 5),
                    m::OnNext(700, 0)
                };
                return m::ToVector(messages);
            }()
        );

        auto ys = scheduler->CreateColdObservable(
            []() {
                ms::RecordedT messages[] = {
                    ms::OnNext(55, "foo"),
                    ms::OnNext(104, "bar"),
                    ms::OnNext(153, "baz"),
                    ms::OnNext(202, "qux"),
                    ms::OnCompleted(251)
                };
                return ms::ToVector(messages);
            }()
        );

        WHEN("each int is mapped to the strings"){

            auto res = scheduler->Start<std::string>(
                [&]() {
                    return observable(from(xs)
                        .select_many([&](int){return ys;}));
                }
            );

            THEN("the output contains strings repeated for each int"){
                ms::RecordedT items[] = {
                    ms::OnNext(355, "foo"),
                    ms::OnNext(404, "bar"),
                    ms::OnNext(453, "baz"),
                    ms::OnNext(455, "foo"),
                    ms::OnNext(502, "qux"),
                    ms::OnNext(504, "bar"),
                    ms::OnNext(553, "baz"),
                    ms::OnNext(555, "foo"),
                    ms::OnNext(602, "qux"),
                    ms::OnNext(604, "bar"),
                    ms::OnNext(653, "baz"),
                    ms::OnNext(655, "foo"),
                    ms::OnNext(702, "qux"),
                    ms::OnNext(704, "bar"),
                    ms::OnNext(753, "baz"),
                    ms::OnNext(755, "foo"),
                    ms::OnNext(802, "qux"),
                    ms::OnNext(804, "bar"),
                    ms::OnNext(853, "baz"),
                    ms::OnNext(902, "qux"),
                    ms::OnNext(955, "foo")
                };
                auto required = ms::ToVector(items);
                auto actual = res->Messages();
                REQUIRE(required == actual);
            }

            THEN("there was one subscription and one unsubscription to the ints"){
                rx::Subscription items[] = {
                    m::Subscribe(200, 1000)
                };
                auto required = m::ToVector(items);
                auto actual = xs->Subscriptions();
                REQUIRE(required == actual);
            }

            THEN("there were four subscription and unsubscription to the strings"){
                rx::Subscription items[] = {
                    ms::Subscribe(300, 551),
                    ms::Subscribe(400, 651),
                    ms::Subscribe(500, 751),
                    ms::Subscribe(600, 851),
                    ms::Subscribe(700, 951),
                    ms::Subscribe(900, 1000)
                };
                auto required = m::ToVector(items);
                auto actual = ys->Subscriptions();
                REQUIRE(required == actual);
            }
        }
    }
}

SCENARIO("select_many inner error", "[select_many][map][operators]"){
    GIVEN("two cold observables. one of ints. one of strings."){
        auto scheduler = std::make_shared<rx::TestScheduler>();
        typedef rx::TestScheduler::Messages<int> m;
        typedef rx::TestScheduler::Messages<std::string> ms;

        long invoked = 0;

        auto xs = scheduler->CreateColdObservable(
            []() {
                m::RecordedT messages[] = {
                    m::OnNext(100, 4),
                    m::OnNext(200, 2),
                    m::OnNext(300, 3),
                    m::OnNext(400, 1),
                    m::OnCompleted(500)
                };
                return m::ToVector(messages);
            }()
        );

        auto ys = scheduler->CreateColdObservable(
            []() {
                ms::RecordedT messages[] = {
                    ms::OnNext(55, "foo"),
                    ms::OnNext(104, "bar"),
                    ms::OnNext(153, "baz"),
                    ms::OnNext(202, "qux"),
                    ms::OnError(301, std::exception())
                };
                return ms::ToVector(messages);
            }()
        );

        WHEN("each int is mapped to the strings"){

            auto res = scheduler->Start<std::string>(
                [&]() {
                    return observable(from(xs)
                        .select_many([&](int){return ys;}));
                }
            );

            THEN("the output contains strings repeated for each int"){
                ms::RecordedT items[] = {
                    ms::OnNext(355, "foo"),
                    ms::OnNext(404, "bar"),
                    ms::OnNext(453, "baz"),
                    ms::OnNext(455, "foo"),
                    ms::OnNext(502, "qux"),
                    ms::OnNext(504, "bar"),
                    ms::OnNext(553, "baz"),
                    ms::OnNext(555, "foo"),
                    ms::OnError(601, std::exception())
                };
                auto required = ms::ToVector(items);
                auto actual = res->Messages();
                REQUIRE(required == actual);
            }

            THEN("there was one subscription and one unsubscription to the ints"){
                rx::Subscription items[] = {
                    m::Subscribe(200, 601)
                };
                auto required = m::ToVector(items);
                auto actual = xs->Subscriptions();
                REQUIRE(required == actual);
            }

            THEN("there were four subscription and unsubscription to the strings"){
                rx::Subscription items[] = {
                    ms::Subscribe(300, 601),
                    ms::Subscribe(400, 601),
                    ms::Subscribe(500, 601),
                    ms::Subscribe(600, 601)
                };
                auto required = ms::ToVector(items);
                auto actual = ys->Subscriptions();
                REQUIRE(required == actual);
            }
        }
    }
}
<|endoftext|>