InfAdoptedAlgorithm: libinfinity-0.7 Reference Manual

## InfAdoptedAlgorithm InfAdoptedAlgorithm — adOPTed implementation |

## Stability Level

Unstable, unless otherwise indicated

## Functions

InfAdoptedAlgorithm * | inf_adopted_algorithm_new ()
InfAdoptedAlgorithm * | inf_adopted_algorithm_new_full ()
InfAdoptedStateVector * | inf_adopted_algorithm_get_current ()
InfAdoptedRequest * | inf_adopted_algorithm_get_execute_request ()
InfAdoptedRequest * | inf_adopted_algorithm_generate_request ()
InfAdoptedRequest * | inf_adopted_algorithm_translate_request ()
gboolean | inf_adopted_algorithm_execute_request ()
void | inf_adopted_algorithm_cleanup ()
gboolean | inf_adopted_algorithm_can_undo ()
gboolean | inf_adopted_algorithm_can_redo ()

## Properties

InfBuffer * | buffer | Read / Write / Construct Only
InfAdoptedStateVector * | buffer-modified-state | Read
InfAdoptedStateVector * | current-state | Read
guint | max-total-log-size | Read / Write / Construct Only
InfUserTable * | user-table | Read / Write / Construct Only

## Signals

void | begin-execute-request | Run Last
void | can-redo-changed | Run Last
void | can-undo-changed | Run Last
void | end-execute-request | Run Last

## Types and Values

enum | InfAdoptedAlgorithmError
struct | InfAdoptedAlgorithm
struct | InfAdoptedAlgorithmClass

## Object Hierarchy

        GObject
        ╰── InfAdoptedAlgorithm

## Includes

    #include <libinfinity/adopted/inf-adopted-algorithm.h>

## Description

InfAdoptedAlgorithm implements the adOPTed algorithm for concurrency control as described in the paper "An integrating, transformation-oriented approach to concurrency control and undo in group editors" by Matthias Ressel, Doris Nitsche-Ruhland and Rul Gunzenhäuser (http://portal.acm.org/citation.cfm?id=240305).

It is based on requests, represented by the InfAdoptedRequest class. If there is at least one local InfUser in the algorithm's user table, then you can create own requests with the `inf_adopted_algorithm_generate_request()` function. Remote requests can be applied via `inf_adopted_algorithm_execute_request()`. This class does not take care of transfering the generated requests to other users which is the scope of InfAdoptedSession.

The implementation is not tied to text editing. It can handle any operations implementing InfAdoptedOperation as long as they define sufficient transformation functions. The libinftext library provides operations for text editing, see InfTextInsertOperation and InfTextDeleteOperation.

## Functions

### inf_adopted_algorithm_new ()

    InfAdoptedAlgorithm *
    inf_adopted_algorithm_new (InfUserTable *user_table,
                               InfBuffer *buffer);

Creates a InfAdoptedAlgorithm.

[constructor]

#### Parameters

user_table | The table of participating users. |
buffer | The buffer to apply operations to. |

#### Returns

A new InfAdoptedAlgorithm.

[transfer full]

### inf_adopted_algorithm_new_full ()

    InfAdoptedAlgorithm *
    inf_adopted_algorithm_new_full (InfUserTable *user_table,
                                    InfBuffer *buffer,
                                    guint max_total_log_size);

Note that it is possible that request logs need to grow a bit larger than `max_total_log_size` in high-latency situations or when a user does not send status updates frequently. However, when all requests have been processed by all users, the sum of all requests in the logs is guaranteed to be lower or equal to this value.

Set to `G_MAXUINT` to disable limitation. In theory, this would allow everyone to undo every operation up to the first one ever made. In practise, this issues a huge amount of data that needs to be synchronized on user join and is too expensive to compute anyway.

The default value is 2048.

[constructor]

#### Parameters

user_table | The table of participating users. |
buffer | The buffer to apply operations to. |
max_total_log_size | The maxmimum number of operations to keep in all user's request logs. |

#### Returns

A new InfAdoptedAlgorithm.

[transfer full]

### inf_adopted_algorithm_get_current ()

    InfAdoptedStateVector *
    inf_adopted_algorithm_get_current (InfAdoptedAlgorithm *algorithm);

Returns the current vector time of `algorithm` .

#### Parameters

algorithm | A InfAdoptedAlgorithm. |

#### Returns

A InfAdoptedStateVector owned by `algorithm` .

[transfer none]

### inf_adopted_algorithm_get_execute_request ()

    InfAdoptedRequest *
    inf_adopted_algorithm_get_execute_request
                                   (InfAdoptedAlgorithm *algorithm);

Returns whether the algorithm is currently transforming a request to the current state and appling its state to the buffer. If it is the function is returning the request that was received and is currently being executed, other wise the function returns `NULL`. Note that the request execution is not re-entrant, i.e. two requests cannot be executed concurrently at the same time, or recursively.

#### Parameters

algorithm | A InfAdoptedAlgorithm. |

#### Returns

The request that `algorithm` is currently processing, or `NULL`. The return value must not be freed by the caller.

[transfer none][allow-none]

### inf_adopted_algorithm_generate_request ()

    InfAdoptedRequest *
    inf_adopted_algorithm_generate_request
                                   (InfAdoptedAlgorithm *algorithm,
                                    InfAdoptedRequestType type,
                                    InfAdoptedUser *user,
                                    InfAdoptedOperation *operation);

Creates a new request that can be applied to the current document state. The request is made by the given user. If operation is of type `INF_ADOPTED_REQUEST_DO`, then `operation` specifies the operation to be performed. Otherwise, `operation` must be `NULL`.

To apply the effect of the request to the document, run `inf_adopted_algorithm_execute_request()`. Note that even if the effect is already applied to the document, the function must still be called with the `apply` parameter set to `FALSE`, so that the algorithm knows that the request has been applied.

#### Parameters

algorithm | A InfAdoptedAlgorithm. |
type | The type of request to create. |
user | The user for which to create the request. |
operation | The operation to perform, or `NULL`. |

#### Returns

A new InfAdoptedRequest. Free with `g_object_unref()` when no longer needed.

[transfer full]

### inf_adopted_algorithm_translate_request ()

    InfAdoptedRequest *
    inf_adopted_algorithm_translate_request
                                   (InfAdoptedAlgorithm *algorithm,
                                    InfAdoptedRequest *request,
                                    InfAdoptedStateVector *to);

Translates `request` so that it can be applied to the document at state `to` . `request` will not be modified but a new, translated request is returned instead.

There are several preconditions for this function to be called. `to` must be a reachable point in the state space. Also, requests can only be translated in forward direction, so `request` 's vector time must be causally before (see `inf_adopted_state_vector_causally_before()`) `to` .

#### Parameters

algorithm | A InfAdoptedAlgorithm. |
request | A InfAdoptedRequest. |
to | The state vector to translate `request` to. | [transfer none]

#### Returns

A new or cached InfAdoptedRequest. Free with `g_object_unref()` when no longer needed.

[transfer full]

### inf_adopted_algorithm_execute_request ()

    gboolean
    inf_adopted_algorithm_execute_request (InfAdoptedAlgorithm *algorithm,
                                           InfAdoptedRequest *request,
                                           gboolean apply,
                                           GError **error);

This function transforms the given request such that it can be applied to the current document state and then applies it the buffer and adds it to the request log of the algorithm, so that it is used for future transformations of other requests.

If `apply` is `FALSE` then the request is not applied to the buffer. In this case, it is assumed that the buffer is already modified, and that the request is made as a result from the buffer modification. This also means that the request must be applicable to the current document state, without requiring transformation.

In addition, the function emits the “begin-execute-request” and “end-execute-request” signals, and makes `inf_adopted_algorithm_get_execute_request()` return `request` during that period.

This allows other code to hook in before and after request processing. This does not cause any loss of generality because this function is not re-entrant anyway: it cannot work when used concurrently by multiple threads nor in a recursive manner, because only when one request has been added to the log the next request can be translated, since it might need the previous request for the translation path and it needs to be translated to a state where the effect of the previous request is included so that it can consistently applied to the buffer.

There are also runtime errors that can occur if `request` execution fails. In this case the function returns `FALSE` and `error` is set. Possible reasons for this include `request` being an `INF_ADOPTED_REQUEST_UNDO` or `INF_ADOPTED_REQUEST_REDO` request without there being an operation to undo or redo, or if the translated operation cannot be applied to the buffer. This usually means that the input `request` was invalid. However, this is not considered a programmer error because typically requests are received from untrusted input sources such as network connections. Note that there cannot be any runtime errors if `apply` is set to `FALSE`. In that case it is safe to call the function with `NULL` error.

#### Parameters

algorithm | A InfAdoptedAlgorithm. |
request | The request to execute. |
apply | Whether to apply the request to the buffer. |
error | Location to store error information, if any. |

#### Returns

`TRUE` on success or `FALSE` on error.

### inf_adopted_algorithm_cleanup ()

    void
    inf_adopted_algorithm_cleanup (InfAdoptedAlgorithm *algorithm);

Removes requests in all users request logs which are no longer needed. This includes requests which cannot be undone or redone anymore due to the constraints of the “max-total-log-size” property, and requests that every participant is guaranteed to have processed already.

This function can be called after every executed request to keep memory use to a minimum, or it can be called in regular intervals, or it can also be omitted if the request history should be preserved.

#### Parameters

algorithm | A InfAdoptedAlgorithm. |

### inf_adopted_algorithm_can_undo ()

    gboolean
    inf_adopted_algorithm_can_undo (InfAdoptedAlgorithm *algorithm,
                                    InfAdoptedUser *user);

Returns whether `user` can issue an undo request in the current state. Note that if `user` is non-local, then the result of this function does not depend on the current state but on the state that we know `user` is guaranteed to have reached. This is because `user` might still issue an Undo request even if the max-total-log-size is already exceeded if `user` does not know yet that it is exceeded.

#### Parameters

algorithm | A InfAdoptedAlgorithm. |
user | A local InfAdoptedUser. |

#### Returns

`TRUE` if Undo is possible, `FALSE` otherwise.

### inf_adopted_algorithm_can_redo ()

    gboolean
    inf_adopted_algorithm_can_redo (InfAdoptedAlgorithm *algorithm,
                                    InfAdoptedUser *user);

Returns whether `user` can issue a redo request in the current state. Note that if `user` is non-local, then the result of this function does not depend on the current state but on the state that we know `user` is guaranteed to have reached. This is because `user` might still issue a Redo request even if the max-total-log-size is already exceeded if `user` does not know yet that it is exceeded.

#### Parameters

algorithm | A InfAdoptedAlgorithm. |
user | A local InfAdoptedUser. |

#### Returns

`TRUE` if Redo is possible, `FALSE` otherwise.

## Types and Values

### enum InfAdoptedAlgorithmError

Error codes for InfAdoptedAlgorithm. These can occur when invalid requests are passed to `inf_adopted_algorithm_execute_request()`.

#### Members

INF_ADOPTED_ALGORITHM_ERROR_NO_UNDO | An undo request was about to be executed but there is no operation to undo. |
INF_ADOPTED_ALGORITHM_ERROR_NO_REDO | A redo request was about to be executed but there is no operation to redo. |
INF_ADOPTED_ALGORITHM_ERROR_FAILED | No further specified error code. |

### struct InfAdoptedAlgorithm

    struct InfAdoptedAlgorithm;

InfAdoptedAlgorithm is an opaque data type. You should only access it via the public API functions.

### struct InfAdoptedAlgorithmClass

    struct InfAdoptedAlgorithmClass {
      void(*can_undo_changed)(InfAdoptedAlgorithm* algorithm,
                              InfAdoptedUser* user,
                              gboolean can_undo);

      void(*can_redo_changed)(InfAdoptedAlgorithm* algorithm,
                              InfAdoptedUser* user,
                              gboolean can_redo);

      void(*begin_execute_request)(InfAdoptedAlgorithm* algorithm,
                                   InfAdoptedUser* user,
                                   InfAdoptedRequest* request);

      void(*end_execute_request)(InfAdoptedAlgorithm* algorithm,
                                 InfAdoptedUser* user,
                                 InfAdoptedRequest* request,
                                 InfAdoptedRequest* translated_request,
                                 const GError* error);
    };

Signals for the InfAdoptedAlgorithm class.

#### Members

`can_undo_changed` () | Default signal handler for the “can_undo_changed” signal. |
`can_redo_changed` () | Default signal handler for the “can_redo_changed” signal. |
`begin_execute_request` () | Default signal handler for the “begin-execute-request” signal. |
`end_execute_request` () | Default signal handler for the “end-execute-request” signal. |

## Property Details

### The `“buffer”` property

      “buffer”                   InfBuffer *

The buffer to apply operations to.

Owner: InfAdoptedAlgorithm

Flags: Read / Write / Construct Only

### The `“buffer-modified-state”` property

      “buffer-modified-state”    InfAdoptedStateVector *

The state in which the buffer is considered not being modified.

Owner: InfAdoptedAlgorithm

Flags: Read

### The `“current-state”` property

      “current-state”            InfAdoptedStateVector *

The state vector describing the current document state.

Owner: InfAdoptedAlgorithm

Flags: Read

### The `“max-total-log-size”` property

      “max-total-log-size”       guint

The maximum number of requests to keep in all user's logs.

Owner: InfAdoptedAlgorithm

Flags: Read / Write / Construct Only

Default value: 2048

### The `“user-table”` property

      “user-table”               InfUserTable *

The user table.

Owner: InfAdoptedAlgorithm

Flags: Read / Write / Construct Only

## Signal Details

### The `“begin-execute-request”` signal

    void
    user_function (InfAdoptedAlgorithm *algorithm,
                   InfAdoptedUser      *user,
                   InfAdoptedRequest   *request,
                   gpointer             user_data)

This signal is emitted every time the algorithm executes a request, i.e. transforms it such that it can be applied to the current state, resolves undo/redo operations and applies the resulting operation to the buffer.

#### Parameters

algorithm | The InfAdoptedAlgorithm executing a request. |
user | The InfAdoptedUser executing the request. |
request | The InfAdoptedRequest being executed. |
user_data | user data set when the signal handler was connected. |

Flags: Run Last

### The `“can-redo-changed”` signal

    void
    user_function (InfAdoptedAlgorithm *algorithm,
                   InfAdoptedUser      *user,
                   gboolean             can_undo,
                   gpointer             user_data)

This signal is emitted every time the can-redo state of a local user in `algorithm` 's user table changed. The can-redo state defines whether `user` can generate a redo request (via `inf_adopted_algorithm_generate_request()`) in the current situation, see also `inf_adopted_algorithm_can_redo()`.

#### Parameters

algorithm | The InfAdoptedAlgorithm for which a user's can-redo state changed. |
user | The InfAdoptedUser whose can-redo state has changed. |
can_undo | Whether `user` can issue a redo request in the current state or not. |
user_data | user data set when the signal handler was connected. |

Flags: Run Last

### The `“can-undo-changed”` signal

    void
    user_function (InfAdoptedAlgorithm *algorithm,
                   InfAdoptedUser      *user,
                   gboolean             can_undo,
                   gpointer             user_data)

This signal is emitted every time the can-undo state of a local user in `algorithm` 's user table changed. The can-undo state defines whether `user` can generate an undo request (via `inf_adopted_algorithm_generate_request()`) in the current situation, see also `inf_adopted_algorithm_can_undo()`.

#### Parameters

algorithm | The InfAdoptedAlgorithm for which a user's can-undo state changed. |
user | The InfAdoptedUser whose can-undo state has changed. |
can_undo | Whether `user` can issue an undo request in the current state or not. |
user_data | user data set when the signal handler was connected. |

Flags: Run Last

### The `“end-execute-request”` signal

    void
    user_function (InfAdoptedAlgorithm *algorithm,
                   InfAdoptedUser      *user,
                   InfAdoptedRequest   *request,
                   InfAdoptedRequest   *translated,
                   GError              *error,
                   gpointer             user_data)

This signal is emitted after a request has been executed. The `request` parameter is not necessarily the same as the one in the corresponding emission of “begin-execute-request”, however its effect on the buffer is the same. The difference is that the request in this signal might be reversible while the request in the “begin-execute-request” emission might not be reversible. The algorithm can make some requests reversible during their execution.

The `translated` request is the result of the transformation, i.e. it is always a `INF_ADOPTED_REQUEST_DO` type request and its state vector corresponds to the current state. It has already been applied on the buffer by the algorithm. If `request` is of type `INF_ADOPTED_REQUEST_UNDO` or `INF_ADOPTED_REQUEST_REDO` then `translated` represents the operation that actually was performed on the buffer to undo or redo the effect of a previous request.

It can happen that an error occurs during execution. Usually this is due to invalid input, such as a request that cannot be transformed to the current state, a `INF_ADOPTED_REQUEST_UNDO` request which has no corresponding `INF_ADOPTED_REQUEST_DO` or `INF_ADOPTED_REQUEST_REDO` request, or a request that ends up in an invalid operation (e.g. inserting text behind the end of the document). If such an error occurs then `request` is the same as the one in the `InfAdoptedAlgorithm`::begin-execute-request emission, `translated` may or may not be `NULL` and `error` contains information on the error occurred.

#### Parameters

algorithm | The InfAdoptedAlgorithm executing a request. |
user | The InfAdoptedUser executing the request. |
request | The InfAdoptedRequest that was executed. |
translated | The result of the request transformation, or `NULL`. |
error | The error that occurred during execution, or `NULL`. |
user_data | user data set when the signal handler was connected. |

Flags: Run Last

## See Also

InfAdoptedSession