Miscellaneous Configuration
This chapter describes several preprocessor macros used to change specific behavior of the Flip framework.
flip_FATAL_MODE
When the Flip framework encounters an operation that put its state to subsequent undefined behavior, it will general a fatal error. The flip_FATAL_MODE
will control how this fatal error is generated. It is for example used when the framework is able to detect an incorrect use of its API.
- if set to
flip_FATAL_MODE_ABORT
, the Flip framework will trigger an abortion on debug and will throw on release, which is most likely desired when developping. This is the default behavior - if set to
flip_FATAL_MODE_THROW
, the Flip framework will throw. This is used in unit testing to ensure that programmers error can be reliably detected - if set to
flip_FATAL_MODE_USER
, theflip_FATAL
macro has to be defined by the user in some appropriate way.
One will activate one option or another using the processor macros or definitions. For example :
flip_FATAL_MODE=flip_FATAL_MODE_THROW |
flip_FATAL
can be defined in a user specific way. To do this define flip_FATAL_MODE
to flip_FATAL_MODE_USER
and provide a definition of it using a compiler option. The best way though is to provide a user config file flip_user_config.h
somewhere in the header search path of the compiler and define flip_HAS_FLIP_USER_CONFIG_H
.
For example such a flip_user_config.h
could look like this:
#pragma once |
#include <cassert> |
extern void trace_error(char* msg); |
#define flip_FATAL { trace_error("FATAL!"); assert(false); throw; } |
Important: Since flip_FATAL
is used as a terminate function, the implementation must make sure that it is never returning. The throw
in the example above ensures this.
flip_NOTHING
Values such as Int
, Float
or Blob
in the flip framework may have conceptually "no value" at specific object life cycles.
- if a value is
added
then itsbefore
value is "no value", - if a value is
removed
then itsvalue
is "no value".
Flip provides two way to represents this value :
- either by implicitely considering that the "no value" is defined and explicitely
0
for numbers or empty for dynamic sized data, usingflip_NOTHING_ZERO
, This is the default behavior, - either considering "no value" to be an error and
flip_FATAL
when attempting to access it, usingflip_NOTHING_FATAL
.
One will activate one option or another using the processor macros or definitions. For example :
flip_NOTHING=flip_NOTHING_FATAL |
flip_ENTITY_USE
The flip Framework Entity
system allows to bind an arbitraty object to a flip Object
or Type
. The system itself is type safe and memory leak safe. However if one does not erase from the Entity
an object it previously emplaced, there is no way for the client of the Flip framework to exactly monitor when the underlying object is going to be effectively freed.
For this reason, the Flip framework allows to detect those situation and may force the developer to erase explicitely the object to ensure it has control over the life span of the object.
- if set to
flip_ENTITY_USE_RELAXED
, the Flip framework will automatically free any remaining object in theEntity
- if set to
flip_ENTITY_USE_STRICT
, the Flip framework will trigger aflip_FATAL
if theEntity
is not empty when the underlying Flip type is removed. This is the default behavior - if set to
flip_ENTITY_USE_PEDANTIC
, the Flip framework will trigger aflip_FATAL
as inflip_ENTITY_USE_STRICT
and will also ensure that any entity creation or erase only occurs from an observer notificationdocument_changed
.
Note: flip_ENTITY_USE
is ignored if flip_ENTITY_LOCATION
is set to flip_ENTITY_LOCATION_NONE
One will activate one option or another using the processor macros or definitions. For example :
flip_ENTITY_USE=flip_ENTITY_USE_RELAXED |
flip_ENTITY_LOCATION
The flip Framework Entity
system allows to bind an arbitraty object to a flip Object
(or derived) or Type
. While being convenient, its memory usage might be a concern if it is only used for object and never for basic types such as Int
or Float
, or never at all.
For this reason, the Flip framework allows either to have the entity available for any kind of Flip object, to restrict only to flip Object
(that is, not any basic types), or to remove completely the feature from Flip.
- if set to
flip_ENTITY_LOCATION_TYPE
, the Flip framework will make theEntity
system available for all types. This is the default behavior - if set to
flip_ENTITY_LOCATION_OBJECT
, the Flip framework will restrict the use ofEntity
to flipObject
only - if set to
flip_ENTITY_LOCATION_NONE
, the Flip framework will remove theEntity
feature
Note: flip_ENTITY_USE
is ignored if flip_ENTITY_LOCATION
is set to flip_ENTITY_LOCATION_NONE
One will activate one option or another using the processor macros or definitions. For example :
flip_ENTITY_LOCATION=flip_ENTITY_LOCATION_OBJECT |
flip_ALLOCATOR_BIND
The flip Framework is using internally an allocator to produce a unique Ref
for every objects that behaves like an address in the global address space of all users/actors sharing the same document. While manipulating a document on the local machine, a mapping is done between the Ref
of a flip object and the underlying Type
pointer.
This binding can be slow and for this reason flip can be configured to use different binding algorithms :
- if set to
flip_ALLOCATOR_BIND_MAP
, the Flip framework will use astd::map
to make the binding. This is the default behavior - if set to
flip_ALLOCATOR_BIND_PANDA
, the Flip framework will use a special algorithm based onstd::deque
to make the binding
flip_ALLOCATOR_BIND_MAP
flip_ALLOCATOR_BIND_MAP
is the most simple and conservative algorithm. Binding and unbinding is slow since a search is done in the std::map
each time.
flip_ALLOCATOR_BIND_PANDA
flip_ALLOCATOR_BIND_PANDA
uses the Ref
allocation properties to accelerate the default behavior, but to the disadvantage to take more memory over time.
Because Ref
allocation always grows, there is more chance for a binding to happen at the end of the mapping list, and so a std::deque
was used since it provides a better memory locality as neighbouring Ref
s are likely to be accessed when executing flip algorithms.
Because std::deque
has non-constant removal time for elements that are not at the beginning or end of the sequence, unbound elements are marked as unbound but not removed from the std::deque
. As a result, the std::deque
will always grow when repeatitivly erasing and inserting elements.
If the memory groth is acceptable to your application and RefAllocator::bind
dominates the time spent in flip when profiling your application, then you might want to use this allocator configuration.