サポートリクエストを送信する前に、このreadmeを注意深く読んで、以前に回答した質問の中に回答が既に存在するかどうかを確認してください。GitHub発行トラッカーを悪用しないでください。
ライブラリ自体は、私の計算によると、約0.5kb :580バイト(最大)のコードと8バイトのメモリの暗黙的なメモリ消費量を持っています。それは、明らかにアイテム自体を保存するために使用されるスペースを考慮していません。
バッファーを宣言するときは、処理する必要があるデータ型とバッファ容量を指定する必要があります。これらの2つのパラメーターは、バッファーによって消費されるメモリに影響します。
# 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
注:上で報告されたメモリ使用法には、ライブラリコードで使用されるプログラムメモリが含まれます。ヒープメモリははるかに少なく、バッファーの同じサイズとタイプの配列に匹敵します。
物事を明確にし始めましょう。ライブラリは、バッファの中央にデータの挿入をサポートしていません。 unshift()
操作を介して最初の要素の前に、またはpush()
操作を介して最後の要素の後にデータをバッファーに追加できます。バッファーの最大容量を超えてデータを追加し続けることができますが、最も重要な情報が失われます。
unshift()
頭に追加するため、容量を超えて尾の要素を上書きして失わせてもらうとpush()
が尾に追加されるため、容量を超えて追加すると、頭の要素が上書きされて失われますunshift()
とpush()
の両方が、追加が情報の損失を引き起こさなかった場合にtrue
を返します。上書きが発生した場合はfalse
:
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
データの追加と同様に、 pop()
操作を介してテールでデータ検索を実行するか、 shift()
操作を介してヘッドから実行できます。
実際のバッファサイズを超えたデータを読み取るには、未定義の動作があり、次のセクションにリストされている追加操作を使用して、このような境界違反を防ぐというユーザーの責任です。ライブラリは、データ型と割り当て方法によって異なる動作を異なりますが、手順を監視しないとプログラムがクラッシュすると安全に想定できます。
非破壊的な読み取り操作も利用できます。
first()
ヘッドの要素を返しますlast()
尾の要素を返します[]
演算子を使用してバッファー内の任意の要素を読み取ることができるアレイのようなインデックス付き読み取り操作も利用できます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()
バッファにデータが保存されていない場合にのみtrue
を返しますisFull()
上書き/データの損失を引き起こすことなく、データをバッファーにさらに追加できない場合にtrue
返しますsize()
バッファに現在保存されている要素の数を返します。境界違反を回避するために[]
演算子と併用する必要があります:最初の要素インデックスは常に0
です(バッファーが空でない場合)、最後の要素インデックスは常にsize() - 1
ですavailable()
バッファを飽和させる前に追加できる要素の数を返しますcapacity()
バッファーが保存できる要素の数を返します。ユーザー定義であり、 1.3.0
から削除された変更を読み取り専用メンバー変数capacity
に置き換えないように、完全性のためにのみ完全性を備えていますclear()
バッファー全体を初期状態にリセットします(ただし、バッファーに動的にオブジェクトを割り当てた場合、そのようなオブジェクトで使用されるメモリはリリースされません。copyToArray(array)
バッファの内容を標準配列array
にコピーします。アレイは、現在バッファにすべての要素を保持するのに十分な大きさでなければなりません。copyToArray(conversionFn, array)
バッファの内容を各要素の関数を実行する標準配列array
(通常はタイプ変換)にコピーします。アレイは、現在バッファにすべての要素を保持するのに十分な大きさでなければなりません。 バージョン1.3.0
から始めて、ライブラリはバッファ容量に基づいてインデックスに使用するデータ型を自動的に検出できます。
65535
超える容量のバッファーを宣言すると、インデックスはunsigned long
になります255
超える宣言された容量を持つバッファー用のunsigned int
byte
で十分ですさらに、同じコードバッファーを小さなインデックスと通常のインデックスでバッファーで混ぜることができます。以前はこれは不可能でした。
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)
上記の最適化の最大の利点を取得するには、バッファインデックスを参照する必要があるときはいつでも、最も適切なタイプを使用する必要があります。これは、次の例のように、 decltype
仕様を使用して簡単に実現できます。
// 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 ();
}
必要に応じて、インデックスタイプをエイリアスして、そのようなエイリアスを参照できます。
using index_t = decltype(buffer):: index_t ;
for ( index_t i = 0 ; i < buffer.size(); i++) {
avg += buffer[i] / buffer. size ();
}
以下は、 1.3.0
以前のバージョンにのみ適用されます。
デフォルトでは、ライブラリはunsigned int
インデックスを使用して、最大65535
アイテムを可能にしますが、このような巨大な店はめったに必要ありません。
ライブラリインデックスを#include
ディレクティブの前にCIRCULAR_BUFFER_XS
マクロを定義するライブラリインデックスをbyte
タイプに切り替えることができます。これにより、ライブラリ自体が使用するメモリが36
バイトしか削減されますが、インデックスアクセスを実行すると、潜在的にさらに絞り出すことができます。小さなデータ型を使用して、いずれかを行います。
# 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]);
}
}
注:このマクロスイッチは、バッファーが8ビットデータ型を内部インデックスとして使用するように強制します。そのため、すべてのバッファーは最大容量255
に制限されます。
ライブラリは、 CIRCULAR_BUFFER_INT_SAFE
マクロスイッチを定義する割り込みで動作するのに役立ちます。これにより、 volatile
修飾子がcount
変数に導入され、ライブラリ全体がコンパイラの最適化を無効にする価格でより割り込みに優しいものにします。 #define
ステートメントは、 #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 );
}
これにより、ライブラリが中断されないことに注意してくださいが、中断駆動型の企業での使用に役立ちます。
ライブラリのexamples
フォルダーでは、複数の例を使用できます。
copyToArray()
関数の使用を示します。 このライブラリを使用して動的に割り当てられたオブジェクトを保存する場合は、メモリの取引を実行しないため、 clear()
メソッドを使用しないでください。バッファコンテンツを反復し、 delete
介して使用される割り当てメソッドをリリースする必要があります( new
)またはfree
( malloc
の場合)を使用していました:
while (!buffer.isEmpty()) {
// pick the correct one
delete buffer. pop ();
free (buffer. pop ());
}
動的に割り当てられたオブジェクトはバッファーからのみ分離されるため、 pop()
およびshift()
操作にもまったく同じことが適用されますが、使用するメモリは自動的にリリースされません(Object.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)
とcopyToArray(array, convertFn)
.h
ヘッダー拡張を.hpp
に切り替えることにより、nano 33 bleとの互換性を追加するshift()
およびpop()
操作の防止操作はバッファを台無しにして誤用します[]
演算子を使用して境界アクセスを防ぐ#2修正#2abort()
はAVR固有です以下の主要な改善のほとんどは、Erlkoenig90:ありがとうNiklasによって提供されました!
capacity
を支持して、メソッドcapacity()
を交換しますEventLogging
を追加し、例Interrupts
CIRCULAT_BUFFER_XS
マクロスイッチを自動インデックスタイプ識別を支持して削除しましたUINT32_MAX
に上がることができます)CIRCULAR_BUFFER_INT_SAFE
を追加しましたmemset
に不必要な呼び出しを削除しましたclear()
関数を修正しましたpop()
関数pop()
およびshift()
実装を修正しましたcapacity()
関数を追加debug()
関数が追加されました