Container standar adalah kumpulan package generik di dalam library standar Ada yang menyediakan struktur data siap pakai, seperti vector, hash map, dan list. Ketiganya berada di dalam anak package Ada.Containers dan diparameterisasi atas tipe elemen, sehingga mekanisme instansiasi subprogram dan package generik langsung terpakai di dalamnya. Topik ini membahas instansiasi tiga container yang sering digunakan, operasi dasarnya, serta kesalahan akses yang muncul saat dibaca melampaui isinya. Contoh yang digunakan adalah deret pembacaan suhu, stok suku cadang, dan daftar peserta piket.
Vector pada Ada.Containers.Vectors#
Ada.Containers.Vectors adalah container generik yang berperilaku seperti array yang dapat bertambah panjang. Container ini diinstansiasi dengan parameter formal Index_Type yang wajib berupa tipe bilangan bulat dan Element_Type untuk isi elemennya. Program berikut menyimpan empat pembacaan suhu, menghitung panjangnya, menelusuri isinya, lalu menghapus satu elemen dari akhir.
with Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Float_Text_IO;
with Ada.Containers.Vectors;
procedure Vektor_Suhu is
-- Instansiasi container generik dari library standar.
package Paket_Vektor is new Ada.Containers.Vectors
(Index_Type => Natural, Element_Type => Float);
Isi : Paket_Vektor.Vector;
begin
Isi.Append (22.5);
Isi.Append (23.0);
Isi.Append (21.5);
Isi.Append (23.5);
Ada.Text_IO.Put ("Jumlah data : ");
Ada.Integer_Text_IO.Put (Integer (Isi.Length), Width => 1);
Ada.Text_IO.New_Line;
Ada.Text_IO.Put ("Data :");
for Nilai of Isi loop
Ada.Text_IO.Put (" ");
Ada.Float_Text_IO.Put (Nilai, Fore => 1, Aft => 1, Exp => 0);
end loop;
Ada.Text_IO.New_Line;
Isi.Delete_Last;
Ada.Text_IO.Put ("Data akhir :");
for I in Isi.First_Index .. Isi.Last_Index loop
Ada.Text_IO.Put (" ");
Ada.Float_Text_IO.Put (Isi.Element (I), Fore => 1, Aft => 1, Exp => 0);
end loop;
Ada.Text_IO.New_Line;
end Vektor_Suhu;# kompilasi program
gnatmake -q vektor_suhu.adb
# jalankan program
./vektor_suhuJumlah data : 4
Data : 22.5 23.0 21.5 23.5
Data akhir : 22.5 23.0 21.5Keluaran memperlihatkan empat data tersimpan dan satu data terakhir terhapus setelah Delete_Last. Fungsi Length mengembalikan nilai bertipe Count_Type, sehingga konversi Integer (Isi.Length) diperlukan sebelum dicetak dengan Ada.Integer_Text_IO. Penelusuran dengan perulangan for Nilai of Isi mengambil setiap elemen tanpa menyentuh indeksnya, sedangkan bentuk kedua menggunakan Isi.Element (I) pada rentang First_Index .. Last_Index.
Operasi Append menambah elemen pada akhir container dan menaikkan panjangnya, sedangkan Delete_Last menurunkannya kembali. Kapasitas internal vector bertumbuh mengikuti kebutuhan, sehingga ukuran awal tidak perlu dinyatakan pada deklarasi objeknya. Pendekatan ini berbeda dengan array biasa yang batasnya terkunci sejak deklarasi, sehingga vector cocok untuk deret data yang panjangnya baru diketahui saat program berjalan.
Hash map pada Ada.Containers.Hashed_Maps#
Ada.Containers.Hashed_Maps menyimpan pasangan kunci dan nilai, dan pencariannya dilakukan melalui fungsi hash (hash function). Instansiasinya membutuhkan empat parameter formal, yaitu Key_Type, Element_Type, Hash, dan Equivalent_Keys. Program berikut mengelola stok suku cadang yang kuncinya berupa kode barang.
with Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Containers.Hashed_Maps;
procedure Stok_Suku_Cadang is
type Kode_Barang is new Integer;
-- Hash sederhana atas kode barang.
function Hash_Kode (Item : Kode_Barang) return Ada.Containers.Hash_Type is
begin
return Ada.Containers.Hash_Type (abs Integer (Item) mod 1_000_003);
end Hash_Kode;
package Paket_Stok is new Ada.Containers.Hashed_Maps
(Key_Type => Kode_Barang,
Element_Type => Natural,
Hash => Hash_Kode,
Equivalent_Keys => "=");
Gudang : Paket_Stok.Map;
begin
Gudang.Insert (1001, 15);
Gudang.Insert (1002, 8);
Gudang.Insert (1003, 24);
-- Include menyisipkan kunci baru, atau mengganti nilainya bila kunci sudah ada.
Gudang.Include (1002, 5);
Ada.Text_IO.Put ("Jumlah kunci : ");
Ada.Integer_Text_IO.Put (Integer (Gudang.Length), Width => 1);
Ada.Text_IO.New_Line;
Ada.Text_IO.Put ("Stok kode 1001 : ");
Ada.Integer_Text_IO.Put (Gudang.Element (1001), Width => 1);
Ada.Text_IO.New_Line;
Ada.Text_IO.Put ("Stok kode 1002 : ");
Ada.Integer_Text_IO.Put (Gudang.Element (1002), Width => 1);
Ada.Text_IO.New_Line;
end Stok_Suku_Cadang;# kompilasi program
gnatmake -q stok_suku_cadang.adb
# jalankan program
./stok_suku_cadangJumlah kunci : 3
Stok kode 1001 : 15
Stok kode 1002 : 5Keluaran memperlihatkan tiga kunci tersimpan, dan stok kode 1002 berubah menjadi 5 karena Include mengganti nilai kunci yang sudah ada. Prosedur Insert berperilaku berbeda, yaitu mengangkat Constraint_Error apabila kunci yang setara sudah terdaftar, sehingga pemilihan antara keduanya bergantung pada maksud pembaruan. Fungsi hash pada contoh ini sengaja sederhana, tetapi syaratnya ketat, yaitu hasilnya harus sama untuk kunci yang setara agar pencarian tetap konsisten.
Fungsi Equivalent_Keys menentukan kapan dua kunci dianggap sama, dan operator = pada contoh ini cukup karena kuncinya bertipe bilangan bulat. Apabila kunci berupa string atau record, fungsi kesetaraan yang sesuai harus disediakan sebagaimana fungsi hash-nya. Kedua fungsi tersebut wajib saling konsisten, karena dua kunci yang setara harus menghasilkan nilai hash yang sama.
List pada Ada.Containers.Doubly_Linked_Lists#
Ada.Containers.Doubly_Linked_Lists menyimpan elemen secara berurutan dalam list bertaut ganda, sehingga penambahan dan penghapusan pada kedua ujungnya murah. Instansiasinya cukup menyebut Element_Type, karena container ini tidak membutuhkan kunci maupun fungsi hash. Program berikut mengelola nomor peserta piket dengan penambahan dari dua arah.
with Ada.Text_IO;
with Ada.Integer_Text_IO;
with Ada.Containers.Doubly_Linked_Lists;
procedure Daftar_Piket is
-- List generik untuk nomor peserta piket.
package Paket_Daftar is new Ada.Containers.Doubly_Linked_Lists
(Element_Type => Natural);
Peserta : Paket_Daftar.List;
begin
Peserta.Append (3);
Peserta.Append (7);
Peserta.Append (5);
Peserta.Prepend (12);
Ada.Text_IO.Put ("Jumlah peserta : ");
Ada.Integer_Text_IO.Put (Integer (Peserta.Length), Width => 1);
Ada.Text_IO.New_Line;
Ada.Text_IO.Put ("Urutan :");
for Nomor of Peserta loop
Ada.Text_IO.Put (" ");
Ada.Integer_Text_IO.Put (Nomor, Width => 1);
end loop;
Ada.Text_IO.New_Line;
Ada.Text_IO.Put ("Pertama : ");
Ada.Integer_Text_IO.Put (Peserta.First_Element, Width => 1);
Ada.Text_IO.New_Line;
Ada.Text_IO.Put ("Terakhir : ");
Ada.Integer_Text_IO.Put (Peserta.Last_Element, Width => 1);
Ada.Text_IO.New_Line;
Peserta.Delete_First;
Ada.Text_IO.Put ("Setelah penghapusan :");
for Nomor of Peserta loop
Ada.Text_IO.Put (" ");
Ada.Integer_Text_IO.Put (Nomor, Width => 1);
end loop;
Ada.Text_IO.New_Line;
end Daftar_Piket;# kompilasi program
gnatmake -q daftar_piket.adb
# jalankan program
./daftar_piketJumlah peserta : 4
Urutan : 12 3 7 5
Pertama : 12
Terakhir : 5
Setelah penghapusan : 3 7 5Keluaran memperlihatkan urutan yang dihasilkan oleh penambahan dua arah, yaitu Append menambah di ekor list dan Prepend menambah di kepalanya. Fungsi First_Element dan Last_Element membaca kedua ujung tanpa penelusuran, sedangkan Delete_First menghapus kepalanya. Ketiga container di atas juga menyediakan cursor, yaitu penunjuk yang dapat bergerak dari satu elemen ke elemen berikutnya, untuk penelusuran yang lebih terkendali daripada perulangan for ... of.
Pemilihan antara vector dan list mengikuti pola aksesnya. Vector menyediakan akses langsung ke indeks mana pun, tetapi penyisipan di tengahnya menuntut pergeseran elemen. List menyimpan elemen dalam simpul bertaut, sehingga penyisipan dan penghapusan di posisi mana pun murah, tetapi pencapaian elemen tengahnya memerlukan penelusuran dari salah satu ujung. Berdasarkan perbedaan perilaku itu, list cocok untuk daftar piket yang sering bertambah dan berkurang isinya.
Kesalahan umum#
Kesalahan akses yang sering terjadi adalah membaca container pada posisi yang belum berisi data. Pada vector, posisi baca wajib berada di dalam rentang First_Index .. Last_Index, dan pelanggarannya mengangkat Constraint_Error.
with Ada.Text_IO;
with Ada.Containers.Vectors;
procedure Baca_Melewati_Error is
package Paket_Vektor is new Ada.Containers.Vectors
(Index_Type => Natural, Element_Type => Float);
Isi : Paket_Vektor.Vector;
begin
Isi.Append (22.5);
Isi.Append (23.0);
-- Index sah 0 .. 1, sedangkan posisi 2 belum berisi data.
Ada.Text_IO.Put_Line (Float'Image (Isi.Element (2)));
exception
when Constraint_Error =>
Ada.Text_IO.Put_Line ("Error: posisi baca melewati isi vektor");
end Baca_Melewati_Error;# kompilasi program
gnatmake -q baca_melewati_error.adb
# jalankan program
./baca_melewati_errorError: posisi baca melewati isi vektorProgram di atas memuat dua data sehingga indeks sahnya adalah 0 sampai 1, sedangkan pembacaan pada posisi 2 sengaja dilakukan untuk memperlihatkan penanganan exception. Perbaikannya adalah memeriksa Length sebelum membaca atau menggunakan rentang First_Index .. Last_Index sebagai batas perulangan. Kesalahan kedua berkaitan dengan cursor, yaitu menyimpan cursor lama setelah isi container berubah. Banyak operasi pengubahan isi membatalkan cursor yang masih menunjuk elemen, sehingga cursor perlu dicari ulang setelah container ditambah atau dikurangi isinya.
Ringkasan#
- Container standar
Ada.Containersadalah package generik yang diinstansiasi per tipe elemen, dan ketiganya menuntut parameter formal yang berbeda. Vectorsmenyimpan elemen berurutan dengan indeks bilangan bulat,Hashed_Mapsmenyimpan pasangan kunci dan nilai dengan fungsi hash, sedangkanDoubly_Linked_Listsmenyimpan elemen bertaut tanpa kunci.Insertpada hash map menolak kunci yang sudah ada, sedangkanIncludemenggantinya, dan pembacaan vector di luar rentang indeksnya mengangkatConstraint_Error.
Referensi#
- Ada Reference Manual 2022, Bagian A.18.2 The Generic Package Containers.Vectors — Ada Resource Association — Menetapkan operasi vector, termasuk Append, Element, dan aturan indeksnya.
- Ada Reference Manual 2022, Bagian A.18.5 The Generic Package Containers.Hashed_Maps — Ada Resource Association — Menetapkan operasi hash map, termasuk perilaku Insert dan Include.
- Ada Reference Manual 2022, Bagian A.18.3 The Generic Package Containers.Doubly_Linked_Lists — Ada Resource Association — Menetapkan operasi list bertaut ganda beserta cursor-nya.
- Standard library: Containers — AdaCore — Memperkenalkan container standar Ada beserta contoh instansiasinya.