ได้โปรดก่อนที่จะส่งคำขอสนับสนุนอ่านอย่างละเอียด readme นี้และตรวจสอบว่ามีคำตอบอยู่แล้วในคำถามที่ได้รับคำตอบก่อนหน้านี้: อย่าใช้ตัวติดตามปัญหา GitHub ในทางที่ผิดหรือไม่
ห้องสมุดมีการใช้หน่วยความจำโดยนัยประมาณ 0.5KB : 580 ไบต์ (สูงสุด) ของรหัสและหน่วยความจำ 8 ไบต์ตามการคำนวณของฉัน นั่นไม่ได้พิจารณาพื้นที่ที่ใช้ในการจัดเก็บสิ่งของด้วยตัวเองอย่างชัดเจน
เมื่อประกาศบัฟเฟอร์ของคุณคุณควรระบุประเภทข้อมูลที่ต้องจัดการและความจุบัฟเฟอร์: พารามิเตอร์ทั้งสองนั้นจะมีผลต่อหน่วยความจำที่ใช้โดยบัฟเฟอร์
# 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
unsigned int
สำหรับบัฟเฟอร์ที่มีความสามารถที่ประกาศมากกว่า 255
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
รายการ แต่คุณจะไม่ต้องการร้านค้าขนาดใหญ่เช่นนี้
คุณสามารถสลับดัชนีไลบรารีเป็นประเภท byte
กำหนดแมโคร CIRCULAR_BUFFER_XS
ก่อน #include
directive: สิ่งนี้จะช่วยลดหน่วยความจำที่ใช้โดยไลบรารีเองเพียง 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
shift()
และ pop()
การใช้งานในทางที่ผิดเพื่อทำให้บัฟเฟอร์ยุ่งเหยิง[]
abort()
เป็นเฉพาะ AVRการปรับปรุงที่สำคัญส่วนใหญ่ด้านล่างได้รับการสนับสนุนจาก Erlkoenig90: ขอบคุณ Niklas!
capacity()
เพื่อ capacity
ของแอตทริบิวต์อินสแตนซ์คงที่EventLogging
และ Interrupts
CIRCULAT_BUFFER_XS
เพื่อสนับสนุนประเภทดัชนีอัตโนมัติUINT32_MAX
)CIRCULAR_BUFFER_INT_SAFE
memset
เมื่อล้างclear()
pop()
แก้ไขpop()
และ shift()
capacity()
ฟังก์ชั่นdebug()
, ปิดใช้งานโดย pre-processor โดยค่าเริ่มต้น