static InfAdoptedSplitOperation* inf_text_default_delete_operation_transform_split( InfTextDeleteOperation* operation, guint split_pos, guint split_len) { InfTextDefaultDeleteOperationPrivate* priv; InfTextChunk* first_chunk; InfTextChunk* second_chunk; GObject* first; GObject* second; InfAdoptedSplitOperation* result; priv = INF_TEXT_DEFAULT_DELETE_OPERATION_PRIVATE(operation); first_chunk = inf_text_chunk_substring(priv->chunk, 0, split_pos); second_chunk = inf_text_chunk_substring( priv->chunk, split_pos, inf_text_chunk_get_length(priv->chunk) - split_pos ); first = g_object_new( INF_TEXT_TYPE_DEFAULT_DELETE_OPERATION, "position", priv->position, "chunk", first_chunk, NULL ); second = g_object_new( INF_TEXT_TYPE_DEFAULT_DELETE_OPERATION, "position", priv->position + split_pos + split_len, "chunk", second_chunk, NULL ); inf_text_chunk_free(first_chunk); inf_text_chunk_free(second_chunk); result = inf_adopted_split_operation_new( INF_ADOPTED_OPERATION(first), INF_ADOPTED_OPERATION(second) ); g_object_unref(first); g_object_unref(second); return result; }
static InfAdoptedOperation* inf_text_remote_delete_operation_copy(InfAdoptedOperation* operation) { InfTextRemoteDeleteOperationPrivate* priv; GObject* result; InfTextRemoteDeleteOperationPrivate* result_priv; priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(operation); result = g_object_new( INF_TEXT_TYPE_REMOTE_DELETE_OPERATION, "position", priv->position, "length", priv->length, NULL ); result_priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(result); result_priv->recon = inf_text_remote_delete_operation_recon_copy( priv->recon ); result_priv->recon_offset = priv->recon_offset; return INF_ADOPTED_OPERATION(result); }
static void inf_adopted_session_noop_timeout_func(gpointer user_data) { InfAdoptedSession* session; InfAdoptedSessionPrivate* priv; InfAdoptedOperation* op; InfAdoptedRequest* request; session = INF_ADOPTED_SESSION(user_data); priv = INF_ADOPTED_SESSION_PRIVATE(session); priv->noop_timeout = NULL; g_assert(priv->next_noop_user != NULL); op = INF_ADOPTED_OPERATION(inf_adopted_no_operation_new()); request = inf_adopted_algorithm_generate_request_noexec( priv->algorithm, priv->next_noop_user->user, op ); g_object_unref(op); /* This resets noop_time for this user, determines the next user for * which to generate a noop request and schedules the new timeout. */ inf_adopted_session_broadcast_request(session, request); g_object_unref(request); }
static void inf_adopted_request_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) { InfAdoptedRequest* request; InfAdoptedRequestPrivate* priv; request = INF_ADOPTED_REQUEST(object); priv = INF_ADOPTED_REQUEST_PRIVATE(request); switch(prop_id) { case PROP_TYPE: priv->type = g_value_get_enum(value); break; case PROP_VECTOR: g_assert(priv->vector == NULL); /* construct only */ priv->vector = g_value_dup_boxed(value); break; case PROP_USER_ID: g_assert(priv->user_id == 0); /* construct only */ g_assert(g_value_get_uint(value) != 0); /* 0 is invalid ID */ priv->user_id = g_value_get_uint(value); break; case PROP_OPERATION: g_assert(priv->operation == NULL); /* construct only */ priv->operation = INF_ADOPTED_OPERATION(g_value_dup_object(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } }
static InfAdoptedOperation* inf_adopted_no_operation_transform(InfAdoptedOperation* operation, InfAdoptedOperation* against, InfAdoptedOperation* operation_lcs, InfAdoptedOperation* against_lcs, gint concurrency_id) { return INF_ADOPTED_OPERATION(inf_adopted_no_operation_new()); }
static InfAdoptedOperation* inf_text_default_insert_operation_revert(InfAdoptedOperation* operation) { InfTextDefaultInsertOperationPrivate* priv; priv = INF_TEXT_DEFAULT_INSERT_OPERATION_PRIVATE(operation); return INF_ADOPTED_OPERATION( inf_text_default_delete_operation_new(priv->position, priv->chunk) ); }
/** * inf_text_delete_operation_transform_insert: * @operation: A #InfTextDeleteOperation. * @against: A #InfTextInsertOperation. * * Returns a new operation that includes the effect of @against into * @operation. * * Return Value: A new #InfAdoptedOperation. **/ InfAdoptedOperation* inf_text_delete_operation_transform_insert(InfTextDeleteOperation* operation, InfTextInsertOperation* against) { InfTextDeleteOperationIface* iface; guint own_pos; guint own_len; guint other_pos; guint other_len; g_return_val_if_fail(INF_TEXT_IS_DELETE_OPERATION(operation), NULL); g_return_val_if_fail(INF_TEXT_IS_INSERT_OPERATION(against), NULL); iface = INF_TEXT_DELETE_OPERATION_GET_IFACE(operation); g_return_val_if_fail(iface->transform_position != NULL, NULL); g_return_val_if_fail(iface->transform_split != NULL, NULL); own_pos = inf_text_delete_operation_get_position(operation); own_len = inf_text_delete_operation_get_length(operation); other_pos = inf_text_insert_operation_get_position(against); other_len = inf_text_insert_operation_get_length(against); if(other_pos >= own_pos + own_len) { return inf_adopted_operation_copy(INF_ADOPTED_OPERATION(operation)); } else if(other_pos <= own_pos) { return INF_ADOPTED_OPERATION( iface->transform_position(operation, own_pos + other_len) ); } else { return INF_ADOPTED_OPERATION( iface->transform_split(operation, other_pos - own_pos, other_len) ); } }
static InfAdoptedOperation* inf_text_default_delete_operation_copy(InfAdoptedOperation* operation) { InfTextDefaultDeleteOperationPrivate* priv; priv = INF_TEXT_DEFAULT_DELETE_OPERATION_PRIVATE(operation); return INF_ADOPTED_OPERATION( g_object_new( INF_TEXT_TYPE_DEFAULT_DELETE_OPERATION, "position", priv->position, "chunk", priv->chunk, NULL ) ); }
static InfAdoptedSplitOperation* inf_text_remote_delete_operation_transform_split( InfTextDeleteOperation* operation, guint split_pos, guint split_len) { /* Need to split the delete operation and the recon list */ InfTextRemoteDeleteOperationPrivate* priv; InfAdoptedSplitOperation* result; GObject* first_operation; GObject* second_operation; InfTextRemoteDeleteOperationPrivate* result_priv; InfTextRemoteDeleteOperationRecon* recon; InfTextRemoteDeleteOperationRecon* new_recon; GSList* first_recon; GSList* second_recon; guint recon_cur_len; GSList* item; priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(operation); first_recon = NULL; second_recon = NULL; recon_cur_len = 0; for(item = priv->recon; item != NULL; item = g_slist_next(item)) { recon = (InfTextRemoteDeleteOperationRecon*)item->data; g_assert(recon->position >= recon_cur_len); if(recon->position - recon_cur_len <= split_pos) { new_recon = g_slice_new(InfTextRemoteDeleteOperationRecon); new_recon->position = recon->position; new_recon->chunk = inf_text_chunk_copy(recon->chunk); first_recon = g_slist_prepend(first_recon, new_recon); recon_cur_len += inf_text_chunk_get_length(recon->chunk); } else { new_recon = g_slice_new(InfTextRemoteDeleteOperationRecon); new_recon->position = recon->position - (split_pos + recon_cur_len); new_recon->chunk = inf_text_chunk_copy(recon->chunk); second_recon = g_slist_prepend(second_recon, new_recon); } } first_operation = g_object_new( INF_TEXT_TYPE_REMOTE_DELETE_OPERATION, "position", priv->position, "length", split_pos, NULL ); second_operation = g_object_new( INF_TEXT_TYPE_REMOTE_DELETE_OPERATION, "position", priv->position + split_len, "length", priv->length - split_pos, NULL ); result_priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(first_operation); result_priv->recon = g_slist_reverse(first_recon); result_priv->recon_offset = priv->recon_offset; result_priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(second_operation); result_priv->recon = g_slist_reverse(second_recon); result_priv->recon_offset = priv->recon_offset + split_pos + recon_cur_len; result = inf_adopted_split_operation_new( INF_ADOPTED_OPERATION(first_operation), INF_ADOPTED_OPERATION(second_operation) ); g_object_unref(G_OBJECT(second_operation)); g_object_unref(G_OBJECT(first_operation)); return result; }
static InfAdoptedOperation* inf_text_remote_delete_operation_apply_transformed(InfAdoptedOperation* op, InfAdoptedOperation* trans, InfAdoptedUser* by, InfBuffer* buffer, GError** error) { InfTextRemoteDeleteOperationPrivate* priv; InfTextChunk* chunk; InfTextChunk* temp_slice; GSList* list; GSList* item; InfAdoptedOperation* operation; GSList* recon_list; GSList* recon_item; InfTextRemoteDeleteOperationRecon* recon; InfTextDefaultDeleteOperation* result; g_assert(INF_TEXT_IS_REMOTE_DELETE_OPERATION(op)); g_assert(INF_TEXT_IS_BUFFER(buffer)); /* TODO: We can probably optimize this function, but then we should * a) profile it and b) in many cases input parameters to this function * are trivial anyway. */ if(INF_ADOPTED_IS_SPLIT_OPERATION(trans)) { list = inf_adopted_split_operation_unsplit( INF_ADOPTED_SPLIT_OPERATION(trans) ); } else { list = g_slist_prepend(NULL, trans); } chunk = inf_text_chunk_new( inf_text_buffer_get_encoding(INF_TEXT_BUFFER(buffer)) ); /* We assume the list of remote delete operations to be in order */ for(item = list; item != NULL; item = g_slist_next(item)) { g_assert(INF_TEXT_IS_REMOTE_DELETE_OPERATION(item->data)); priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(item->data); operation = INF_ADOPTED_OPERATION(item->data); if(priv->length > 0) { temp_slice = inf_text_buffer_get_slice( INF_TEXT_BUFFER(buffer), priv->position, priv->length ); recon_list = inf_text_remote_delete_operation_recon_feed( priv->recon, 0, temp_slice ); inf_text_chunk_free(temp_slice); } else { recon_list = priv->recon; } for(recon_item = recon_list; recon_item != NULL; recon_item = g_slist_next(recon_item)) { recon = (InfTextRemoteDeleteOperationRecon*)recon_item->data; g_assert(priv->recon_offset + recon->position == inf_text_chunk_get_length(chunk)); inf_text_chunk_insert_chunk( chunk, inf_text_chunk_get_length(chunk), recon->chunk ); } /* Free recon list if newly allocated */ if(priv->length > 0) inf_text_remote_delete_operation_recon_free(recon_list); if(!inf_adopted_operation_apply(operation, by, buffer, error)) { g_slist_free(list); inf_text_chunk_free(chunk); return NULL; } } g_slist_free(list); priv = INF_TEXT_REMOTE_DELETE_OPERATION_PRIVATE(op); result = inf_text_default_delete_operation_new(priv->position, chunk); inf_text_chunk_free(chunk); return INF_ADOPTED_OPERATION(result); }
static InfAdoptedOperation* inf_adopted_no_operation_revert(InfAdoptedOperation* operation) { return INF_ADOPTED_OPERATION(inf_adopted_no_operation_new()); }
/** * inf_text_delete_operation_transform_delete: * @operation: A #InfTextDeleteOperation. * @against: Another #InfTextDeleteOperation. * * Returns a new operation that includes the effect of @against into * @operation. * * Return Value: A new #InfAdoptedOperation. **/ InfAdoptedOperation* inf_text_delete_operation_transform_delete(InfTextDeleteOperation* operation, InfTextDeleteOperation* against) { InfTextDeleteOperationIface* iface; guint own_pos; guint own_len; guint other_pos; guint other_len; g_return_val_if_fail(INF_TEXT_IS_DELETE_OPERATION(operation), NULL); g_return_val_if_fail(INF_TEXT_IS_DELETE_OPERATION(against), NULL); iface = INF_TEXT_DELETE_OPERATION_GET_IFACE(operation); g_return_val_if_fail(iface->transform_position != NULL, NULL); g_return_val_if_fail(iface->transform_overlap != NULL, NULL); own_pos = inf_text_delete_operation_get_position(operation); own_len = inf_text_delete_operation_get_length(operation); other_pos = inf_text_delete_operation_get_position(against); other_len = inf_text_delete_operation_get_length(against); if(own_pos + own_len <= other_pos) { return inf_adopted_operation_copy(INF_ADOPTED_OPERATION(operation)); } else if(own_pos >= other_pos + other_len) { return INF_ADOPTED_OPERATION( iface->transform_position(operation, own_pos - other_len) ); } /* Somehow overlapping now */ else if(other_pos <= own_pos && other_pos + other_len >= own_pos + own_len) { return INF_ADOPTED_OPERATION( iface->transform_overlap( operation, against, other_pos, 0, own_pos - other_pos, own_len ) ); } else if(other_pos <= own_pos && other_pos + other_len < own_pos + own_len) { return INF_ADOPTED_OPERATION( iface->transform_overlap( operation, against, other_pos, 0, own_pos - other_pos, other_pos + other_len - own_pos ) ); } else if(other_pos > own_pos && other_pos + other_len >= own_pos + own_len) { return INF_ADOPTED_OPERATION( iface->transform_overlap( operation, against, own_pos, other_pos - own_pos, 0, own_pos + own_len - other_pos ) ); } else { return INF_ADOPTED_OPERATION( iface->transform_overlap( operation, against, own_pos, other_pos - own_pos, 0, other_len ) ); } }
/** * inf_text_insert_operation_transform_insert: * @operation: A #InfTextInsertOperation. * @against: Another #InfTextInsertOperation. * @op_lcs: The given operation in a previous state, or %NULL. * @ag_lcs: The @against operation in a previous state, or %NULL. * @cid: The concurrency ID for the transformation. * * Returns a new operation that includes the effect of @against into * @operation. * * Return Value: A new #InfAdoptedOperation. **/ InfAdoptedOperation* inf_text_insert_operation_transform_insert(InfTextInsertOperation* operation, InfTextInsertOperation* against, InfTextInsertOperation* op_lcs, InfTextInsertOperation* ag_lcs, InfAdoptedConcurrencyId cid) { InfTextInsertOperationIface* iface; guint op_pos; guint against_pos; guint op_lcs_pos; guint against_lcs_pos; guint against_length; g_return_val_if_fail(INF_TEXT_IS_INSERT_OPERATION(operation), NULL); g_return_val_if_fail(INF_TEXT_IS_INSERT_OPERATION(against), NULL); iface = INF_TEXT_INSERT_OPERATION_GET_IFACE(operation); g_return_val_if_fail(iface->transform_position != NULL, NULL); op_pos = inf_text_insert_operation_get_position(operation); against_pos = inf_text_insert_operation_get_position(against); if(op_pos < against_pos) { return inf_adopted_operation_copy(INF_ADOPTED_OPERATION(operation)); } else if(op_pos > against_pos) { against_length = inf_text_insert_operation_get_length(against); return INF_ADOPTED_OPERATION( iface->transform_position(operation, op_pos + against_length) ); } else { g_assert(op_lcs != NULL); g_assert(ag_lcs != NULL); op_lcs_pos = inf_text_insert_operation_get_position(op_lcs); against_lcs_pos = inf_text_insert_operation_get_position(ag_lcs); if(op_lcs_pos < against_lcs_pos || (op_lcs_pos == against_lcs_pos && cid == INF_ADOPTED_CONCURRENCY_OTHER)) { return inf_adopted_operation_copy(INF_ADOPTED_OPERATION(operation)); } else if(op_lcs_pos > against_lcs_pos || (op_lcs_pos == against_lcs_pos && cid == INF_ADOPTED_CONCURRENCY_SELF)) { against_length = inf_text_insert_operation_get_length(against); return INF_ADOPTED_OPERATION( iface->transform_position(operation, op_pos + against_length) ); } else { g_assert_not_reached(); return NULL; } } }