S'il vous plaît, avant de soumettre une demande d'assistance, lisez attentivement cette lecture et vérifiez si une réponse existe déjà parmi les questions précédemment répondues: n'abusez pas du suivi du problème GitHub.
La bibliothèque elle-même a une consommation de mémoire implicite d'environ 0,5 Ko : 580 octets (max) de code et 8 octets de mémoire, selon mes calculs. Cela ne considère pas l'espace utilisé pour stocker les articles eux-mêmes, évidemment.
Lorsque vous déclarez votre tampon, vous devez spécifier le type de données qu'il doit gérer et la capacité du tampon: ces deux paramètres influenceront la mémoire consommée par le tampon.
# include < CircularBuffer.hpp >
CircularBuffer<byte, 100 > bytes; // uses 538 bytes
CircularBuffer< int , 100 > ints; // uses 638 bytes
CircularBuffer< long , 100 > longs; // uses 838 bytes
CircularBuffer< float , 100 > floats; // uses 988 bytes
CircularBuffer< double , 100 > doubles; // uses 988 bytes
CircularBuffer< char , 100 > chars; // uses 538 bytes
CircularBuffer< void *, 100 > pointers; // uses 638 bytes
Veuillez noter : L'utilisation de la mémoire indiquée ci-dessus comprend la mémoire du programme utilisée par le code de la bibliothèque, la mémoire du tas est beaucoup moindre et est comparable à un tableau de la même taille et du même type de tampon.
Commençons à clarifier les choses: la bibliothèque ne prend pas en charge l'insertion de données au milieu du tampon. Vous pouvez ajouter des données au tampon avant le premier élément via une opération unshift()
ou après le dernier élément via une opération push()
. Vous pouvez continuer à ajouter des données au-delà de la capacité maximale du tampon, mais vous perdrez les informations les moins significatives:
unshift()
s'ajoute à la tête , l'ajout au-delà de la capacité fait écraser et perdu l'élément de la queue et perdupush()
s'ajoute à la queue , l'ajout au-delà de la capacité fait écraser et perdu l'élément de la tête et perdu unshift()
et push()
Retourne true
si l'ajout n'a provoqué aucune perte d'informations, false
si un écrasement s'est produit:
CircularBuffer< int , 5 > buffer; // buffer capacity is 5
// all of the following return true
buffer.unshift( 1 ); // [1]
buffer.unshift( 2 ); // [2,1]
buffer.unshift( 3 ); // [3,2,1]
buffer.push( 0 ); // [3,2,1,0]
buffer.push( 5 ); // [3,2,1,0,5]
// buffer is now at full capacity, from now on any addition returns false
buffer.unshift( 2 ); // [2,3,2,1,0] returns false
buffer.unshift( 10 ); // [10,2,3,2,1] returns false
buffer.push(- 5 ); // [2,3,2,1,-5] returns false
De façon similaire à l'addition de données, la récupération des données peut être effectuée à la queue via une opération pop()
ou de la tête via une opération shift()
: les deux provoquent la suppression de l'élément lu du tampon.
La lecture des données au-delà de la taille réelle du tampon a un comportement non défini et est la responsabilité de l'utilisateur de prévenir de telles violations des limites en utilisant les opérations supplémentaires répertoriées dans la section suivante. La bibliothèque se comportera différemment en fonction du type de données et de la méthode d'allocation, mais vous pouvez supposer en toute sécurité que votre programme se bloquera si vous ne regardez pas vos étapes.
Des opérations de lecture non destructeurs sont également disponibles:
first()
renvoie l'élément à la têtelast()
renvoie l'élément à la queue[]
CircularBuffer< char , 50 > buffer; // ['a','b','c','d','e','f','g']
buffer.first(); // ['a','b','c','d','e','f','g'] returns 'a'
buffer.last(); // ['a','b','c','d','e','f','g'] returns 'g'
buffer.pop(); // ['a','b','c','d','e','f'] returns 'g'
buffer.pop(); // ['a','b','c','d','e'] returns 'f'
buffer.shift(); // ['b','c','d','e'] returns 'a'
buffer.shift(); // ['c','d','e'] returns 'b'
buffer[ 0 ]; // ['c','d','e'] returns 'c'
buffer[ 1 ]; // ['c','d','e'] returns 'd'
buffer[ 2 ]; // ['c','d','e'] returns 'e'
buffer[ 10 ]; // ['c','d','e'] returned value is unpredictable
buffer[ 15 ]; // ['c','d','e'] returned value is unpredictable
isEmpty()
Renvoie true
uniquement si aucune donnée n'est stockée dans le tamponisFull()
renvoie true
si aucune donnée ne peut être ajoutée au tampon sans provoquer des substances substancesuses / pertes de donnéessize()
renvoie le nombre d'éléments actuellement stockés dans le tampon; Il doit être utilisé en conjonction avec l'opérateur []
pour éviter les violations des limites: le premier indice d'élément est toujours 0
(si le tampon n'est pas vide), le dernier index d'élément est toujours size() - 1
available()
renvoie le nombre d'éléments qui peuvent être ajoutés avant de saturer le tamponcapacity()
Renvoie le nombre d'éléments que le tampon peut stocker, pour l'exhaustivité uniquement car il est défini par l'utilisateur et ne modifie jamais la suppression de 1.3.0
remplacée par la capacity
variable de membre en lecture seuleclear()
réinitialise l'ensemble du tampon à son état initial (faites attention cependant, si vous aviez des objets alloués dynamiquement dans votre tampon, la mémoire utilisée par un tel objet n'est pas libérée: itérez le contenu du tampon et libérez les objets en conséquence à leur méthode d'allocation)copyToArray(array)
Copie le contenu du tampon dans un array
de tableau standard. Le tableau doit être suffisamment grand pour contenir tous les éléments actuellement dans le tampon.copyToArray(conversionFn, array)
Copie le contenu du tampon en un array
de tableau standard exécutant une fonction sur chaque élément, généralement une conversion de type. Le tableau doit être suffisamment grand pour contenir tous les éléments actuellement dans le tampon. À partir de la version 1.3.0
la bibliothèque est capable de détecter automatiquement le type de données doit être utilisé pour l'indice en fonction de la capacité de tampon:
65535
, votre indice sera un unsigned long
unsigned int
pour les tampons avec une capacité déclarée supérieure à 255
byte
va suffireDe plus, vous pouvez mélanger les mêmes tampons de code avec un petit index et des tampons avec un index normal: auparavant, cela n'était pas possible.
CircularBuffer< char , 100 > optimizedBuffer; // reduced memory footprint, index type is uint8_t (a.k.a. byte)
CircularBuffer< long , 500 > normalBuffer; // standard memory footprint, index type is unit16_t (a.k.a. unsigned int)
CircularBuffer< int , 66000 > hugeBuffer; // extended memory footprint, index type is unit32_t (a.k.a. unsigned long)
Pour obtenir l'avantage maximum de l'optimisation ci-dessus, chaque fois que vous devez vous référer à l'indice de tampon, vous devez utiliser le type le plus approprié: cela peut être facilement réalisé en utilisant le spécificateur decltype
, comme dans l'exemple suivant:
// the iterator variable i is of the correct type, even if
// we don't know what's the buffer declared capacity
for (decltype(buffer):: index_t i = 0 ; i < buffer.size(); i++) {
avg += buffer[i] / buffer. size ();
}
Si vous préférez, vous pouvez alimenter le type d'index et vous référer à ces alias:
using index_t = decltype(buffer):: index_t ;
for ( index_t i = 0 ; i < buffer.size(); i++) {
avg += buffer[i] / buffer. size ();
}
Ce qui suit s'applique aux versions avant 1.3.0
uniquement.
Par défaut, la bibliothèque utilise des index unsigned int
, permettant un maximum de 65535
articles, mais vous aurez rarement besoin d'un magasin aussi énorme.
Vous pouvez basculer les index de la bibliothèque en type byte
définissant la macro CIRCULAR_BUFFER_XS
avant la directive #include
: cela réduit la mémoire utilisée par la bibliothèque elle-même par seulement 36
octets, mais vous permet de vous exprimer beaucoup plus chaque fois que vous effectuez un accès indexé, si Vous en faites, en utilisant le type de données plus petit.
# define CIRCULAR_BUFFER_XS
# include < CircularBuffer.h >
CircularBuffer< short , 100 > buffer;
void setup () { }
void loop () {
// here i should be declared of type byte rather than unsigned int
// in order to maximize the effects of the optimization
for (byte i = 0 ; i < buffer. size () - 1 ; i++) {
Serial. print (buffer[i]);
}
}
Veuillez noter : Ce commutateur de macro force le tampon à utiliser un type de données de 8 bits comme indice interne, en tant que tel, tous vos tampons seront limités à une capacité maximale de 255
.
La bibliothèque aide à travailler avec des interruptions définissant le commutateur macro CIRCULAR_BUFFER_INT_SAFE
, qui introduit le modificateur volatile
à la variable count
, ce qui rend la bibliothèque entière plus conviviale au prix de la désactivation de certaines optimisations du compilateur. L'instruction #define
doit être placée quelque part avant la déclaration #include
:
# define CIRCULAR_BUFFER_INT_SAFE
# include < CircularBuffer.h >
CircularBuffer< unsigned long , 10 > timings;
void count () {
timings. push ( millis ());
}
void setup () {
attachInterrupt ( digitalPinToInterrupt ( 2 ), count, RISING);
}
void loop () {
Serial. print ( " buffer size is " ); Serial. println (timings. size ());
delay ( 250 );
}
Veuillez noter que cela ne permet pas à l' interruption de la bibliothèque, mais cela aide son utilisation dans l'interruption Firmwares.
Plusieurs exemples sont disponibles dans le dossier examples
de la bibliothèque:
copyToArray()
. Si vous utilisez cette bibliothèque pour stocker des objets alloués dynamiquement, absorbent l'utilisation de la méthode clear()
car cela n'effectuera pas la mémoire de la mémoire: vous devez itérer sur votre contenu tampon et libérer la mémoire en conséquence de la méthode d'allocation utilisée, soit via delete
(si Vous aviez utilisé new
) ou free
(dans le cas de malloc
):
while (!buffer.isEmpty()) {
// pick the correct one
delete buffer. pop ();
free (buffer. pop ());
}
Le même s'applique aux opérations pop()
et shift()
car tout objet alloué dynamiquement n'est détaché que du tampon, mais la mémoire qu'il utilise n'est pas libérée automatique (voir l'exemple objet.ino)
Record* record = new Record(millis(), sample); // a dynamically allocated object
buffer.push(record);
// somewhere else
if (!buffer.isEmpty()) {
Record* current = buffer. pop ();
Serial. println (current. value ());
delete current; // if you don't do this the object memory is lost!!!
}
copyToArray(array)
et copyToArray(array, convertFn)
.h
Extension d'en-tête à .hpp
shift()
et pop()
Les opérations abutent pour gâcher le tampon[]
abort()
est spécifique à l'AVRLa plupart des principales améliorations ci-dessous ont été apportées par Erlkoenig90: Merci Niklas!
capacity()
en faveur de la capacity
d'attribut d'instance constanteEventLogging
et Interrupts
CIRCULAT_BUFFER_XS
en faveur de l'identification automatique du type d'indexUINT32_MAX
)CIRCULAR_BUFFER_INT_SAFE
memset
lors de la défrichementclear()
pop()
fixepop()
et shift()
fixescapacity()
ajoutéedebug()
, désactivée par le pré-processeur par défaut