/* libobby - Network text editing library
* Copyright (C) 2005, 2006 0x539 dev group
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "jupiter_algorithm.hpp"
#if 0
obby::jupiter_algorithm::operation_wrapper::
operation_wrapper(unsigned int count, const operation& op)
: m_count(count), m_operation(op.clone() )
{
}
obby::jupiter_algorithm::operation_wrapper::
operation_wrapper(unsigned int count, operation* op)
: m_count(count), m_operation(op)
{
if(op != NULL) return;
throw std::logic_error(
"obby::jupiter_algorithm::operation_wrapper::operation_wrapper"
);
}
unsigned int obby::jupiter_algorithm::operation_wrapper::get_count() const
{
return m_count;
}
const obby::operation&
obby::jupiter_algorithm::operation_wrapper::get_operation() const
{
return *m_operation;
}
void obby::jupiter_algorithm::operation_wrapper::
reset_operation(const operation& new_op)
{
m_operation.reset(new_op.clone() );
}
void obby::jupiter_algorithm::operation_wrapper::
reset_operation(operation* new_op)
{
if(new_op != NULL)
{
m_operation.reset(new_op);
return;
}
throw std::logic_error(
"obby::jupiter_algorithm::operation_wrapper::reset_operation"
);
}
obby::jupiter_algorithm::jupiter_algorithm()
: m_time(0, 0)
{
}
obby::jupiter_algorithm::~jupiter_algorithm()
{
for(ack_list::iterator iter = m_ack_list.begin();
iter != m_ack_list.end();
++ iter)
{
delete *iter;
}
}
std::auto_ptr<obby::record>
obby::jupiter_algorithm::local_op(const operation& op)
{
// Generate request
std::auto_ptr<record> rec(new record(m_time, op) );
// Add to outgoing queue
m_ack_list.push_back(new operation_wrapper(m_time.get_local(), op) );
// Generated new message
m_time.inc_local();
// Return request
return rec;
}
std::auto_ptr<obby::operation>
obby::jupiter_algorithm::remote_op(const record& rec)
{
// Check preconditions before transforming
check_preconditions(rec);
// Discard acknowledged operations
discard_operations(rec);
// Transform operation
std::auto_ptr<operation> op(transform(rec.get_operation()) );
// Got new message
m_time.inc_remote();
// Return transformed operation
return op;
}
void obby::jupiter_algorithm::discard_operations(const record& rec)
{
for(ack_list::iterator iter = m_ack_list.begin();
iter != m_ack_list.end();)
{
// Already acknowledged?
if( (*iter)->get_count() < rec.get_time().get_remote() )
{
// Delete operation
delete *iter;
// Remove from list
//iter = m_ack_list.erase(iter);
}
else
{
// Check next one
// TODO: Newer operations won't be acknowledged either,
// so break here?
++ iter;
}
}
// Verify sequence order
if(rec.get_time().get_local() != m_time.get_remote() )
{
throw std::logic_error(
"obby::jupiter_algorithm::discard_operations"
);
}
}
std::auto_ptr<obby::operation>
obby::jupiter_algorithm::transform(const operation& op) const
{
std::auto_ptr<operation> new_op(op.clone() );
for(ack_list::const_iterator iter = m_ack_list.begin();
iter != m_ack_list.end();
++ iter)
{
// Get current operation in list
const operation* existing_op = &(*iter)->get_operation();
// Transform new operation against existing one
operation* new_trans_op = existing_op->transform(*new_op);
// Transform existing operation against new one
operation* existing_trans_op = new_op->transform(*existing_op);
// Replace existing operation by transformed one
(*iter)->reset_operation(existing_trans_op);
// Replace new operation by transformed one
new_op.reset(new_trans_op);
}
return new_op;
}
void obby::jupiter_algorithm::check_preconditions(const record& rec) const
{
// #1
if(!m_ack_list.empty() &&
rec.get_time().get_remote() < m_ack_list.front()->get_count() )
{
throw std::logic_error(
"obby::jupiter_algorithm::check_preconditions (#1)"
);
}
// #2
if(rec.get_time().get_remote() > m_time.get_local() )
{
throw std::logic_error(
"obby::jupiter_algorithm::check_preconditions (#2)"
);
}
// #3
if(rec.get_time().get_local() != m_time.get_remote() )
{
throw std::logic_error(
"obby::jupiter_algorithm::check_preconditions (#3)"
);
}
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1