Ένας κυκλικός buffer, ένας επανακυκλούμενος buffer ή ένας buffer δακτυλίου είναι μια δομή δεδομένων που χρησιμοποιεί έναν μόνο buffer σταθερού μεγέθους, σαν να ήταν συνδεδεμένος από άκρη σε άκρη.
Ένας κυκλικός buffer ξεκινάει κενός και με κάποιο προκαθορισμένο μήκος. Για παράδειγμα, αυτός είναι ένας buffer 7 στοιχείων:
[ ][ ][ ][ ][ ][ ][ ]
Ας υποθέσουμε ότι ένα 1 γράφεται στη μέση του buffer (η ακριβής αρχική θέση δεν έχει σημασία σε έναν κυκλικό buffer):
[ ][ ][ ][1][ ][ ][ ]
Έπειτα, ας υποθέσουμε ότι προστίθενται άλλα δύο στοιχεία, το 2 και το 3, τα οποία προσαρτώνται μετά το 1:
[ ][ ][ ][1][2][3][ ]
Αν στη συνέχεια αφαιρεθούν δύο στοιχεία από τον buffer, αφαιρούνται οι παλαιότερες τιμές που υπάρχουν μέσα του. Τα δύο στοιχεία που αφαιρούνται, στην περίπτωση αυτή, είναι το 1 και το 2, αφήνοντας τον buffer με ένα μόνο 3:
[ ][ ][ ][ ][ ][3][ ]
Αν ο buffer έχει 7 στοιχεία, τότε είναι τελείως γεμάτος:
[5][6][7][8][9][3][4]
Όταν ο buffer γεμίσει, πετάγεται ένα σφάλμα, ειδοποιώντας τον client ότι περαιτέρω εγγραφές μπλοκάρονται μέχρι να ελευθερωθεί μια θέση.
Όταν ο buffer είναι γεμάτος, ο client μπορεί να επιλέξει να αντικαταστήσει τα παλαιότερα δεδομένα με μια εξαναγκασμένη εγγραφή. Στην περίπτωση αυτή, προστίθενται άλλα δύο στοιχεία, το A και το B, τα οποία αντικαθιστούν το 3 και το 4:
[5][6][7][8][9][A][B]
Τα 3 και 4 έχουν αντικατασταθεί από τα A και B, κάνοντας το 5 τα παλαιότερα δεδομένα μέσα στον buffer. Τέλος, αν αφαιρεθούν δύο στοιχεία, αυτό που θα επιστραφεί είναι τα 5 και 6, δίνοντας τον buffer:
[ ][ ][7][8][9][A][B]
Επειδή υπάρχει διαθέσιμος χώρος, αν ο client χρησιμοποιήσει ξανά την αντικατάσταση για να αποθηκεύσει το C και το D, τότε θα χρησιμοποιηθεί ο χώρος όπου ήταν αποθηκευμένα προηγουμένως το 5 και το 6, και όχι η θέση του 7 και του 8. Το 7 εξακολουθεί να είναι το παλαιότερο στοιχείο και ο buffer είναι για άλλη μια φορά γεμάτος.
[C][D][7][8][9][A][B]
Μερικές φορές χρειάζεται και να προσαρμόσεις και να κάνεις raise εξαιρέσεις στον κώδικά σου. Όταν το κάνεις αυτό, πρέπει πάντα να συμπεριλαμβάνεις ένα ουσιαστικό μήνυμα σφάλματος που να δείχνει ποια είναι η πηγή του σφάλματος. Αυτό κάνει τον κώδικά σου πιο ευανάγνωστο και βοηθάει σημαντικά στο debugging.
Οι προσαρμοσμένες εξαιρέσεις μπορούν να δημιουργηθούν μέσα από νέες κλάσεις εξαιρέσεων (δες classes για περισσότερες λεπτομέρειες) που κατά κανόνα είναι υποκλάσεις της Exception.
Σε περιπτώσεις όπου ξέρεις ότι η πηγή του σφάλματος θα είναι παράγωγο ενός συγκεκριμένου τύπου εξαίρεσης, μπορείς να επιλέξεις να κληρονομήσεις από έναν από τους built in error types κάτω από την κλάση Exception. Όταν πετάς το σφάλμα, θα πρέπει και πάλι να συμπεριλάβεις ένα ουσιαστικό μήνυμα.
Αυτή η συγκεκριμένη άσκηση απαιτεί να δημιουργήσεις δύο προσαρμοσμένες εξαιρέσεις. Τη μία εξαίρεση να την πετάξεις/"ρίξεις" όταν ο κυκλικός buffer σου είναι γεμάτος, και μία για όταν είναι άδειος. Τα tests θα περάσουν μόνο αν προσαρμόσεις κατάλληλες εξαιρέσεις, τις πετάξεις με raise και συμπεριλάβεις κατάλληλα μηνύματα σφάλματος.
Για να προσαρμόσεις μια built-in exception, δημιούργησε μια class που κληρονομεί από αυτή την εξαίρεση. Όταν πετάς την προσαρμοσμένη εξαίρεση με ένα μήνυμα, γράψε το μήνυμα ως όρισμα στον τύπο exception:
# subclassing the built-in BufferError to create BufferFullException
class BufferFullException(BufferError):
"""Exception raised when CircularBuffer is full.
message: explanation of the error.
"""
def __init__(self, message):
self.message = message
# raising a BufferFullException
raise BufferFullException("Circular buffer is full")
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Python με 17 έννοιες146 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.
Σε αυτό το βίντεο ρίχνουμε μια ματιά στον κυκλικό buffer, τι είναι, πού χρησιμοποιείται και διάφορες υλοποιήσεις, όπως ουρές, στατικούς και δυναμικούς πίνακες, αμετάβλητες δομές δεδομένων και μια διασκεδαστική υλοποίηση βασισμένη σε agents.