تطبيق هاشماب بسيط لرأس واحد لـ C/C++.
ما عليك سوى #include "hashmap.h"
في التعليمات البرمجية الخاصة بك!
المترجمات المدعومة حاليًا هي gcc و clang و msvc.
الأنظمة الأساسية المدعومة حاليًا هي Linux وmacOS وWindows.
تم تصميم خريطة التجزئة للعمل مع أي مفاتيح بيانات عشوائية - ما عليك سوى توفير المؤشر والحجم، وسوف تقوم بتجزئة تلك البيانات. أداة التجزئة الافتراضية هي متغير crc32 يستخدم جوهر الأجهزة إن أمكن، والمقارن الافتراضي يستخدم memcmp
فقط، لذا يُنصح بإلغاء أي مساحة في مفاتيح البنية.
لإنشاء خريطة هاشماب، قم باستدعاء وظيفة hashmap_create
:
const unsigned initial_size = 2 ;
struct hashmap_s hashmap ;
if ( 0 != hashmap_create ( initial_size , & hashmap )) {
// error!
}
تقوم المعلمة initial_size
فقط بتعيين الحجم الأولي لخريطة التجزئة - والتي يمكن أن تنمو إذا وصلت عدة مفاتيح إلى نفس إدخال التجزئة. يتم تقريب حجم علامة التجزئة إلى أقرب قوة اثنين فوق initial_size
المقدم.
هناك أيضًا وظيفة إنشاء موسعة hashmap_create_ex
:
struct hashmap_s hashmap ;
struct hashmap_create_options_s options ;
memset ( & options , 0 , sizeof ( options ));
// You can set a custom hasher that the hashmap should use.
options . hasher = & my_hasher ;
// You can set a custom comparer that the hashmap should for comparing keys.
options . comparer = & my_comparer ;
// You can also specify the initial capacity of the hashmap.
options . initial_capacity = 42 ;
if ( 0 != hashmap_create_ex ( options , & hashmap )) {
// error!
}
لوضع عنصر في hashmap استخدم وظيفة hashmap_put
:
int meaning_of_life = 42 ;
char question = 6 * 8 ;
if ( 0 != hashmap_put ( & hashmap , "life" , strlen ( "life" ), & meaning_of_life )) {
// error!
}
if ( 0 != hashmap_put ( & hashmap , "?" , strlen ( "?" ), & question )) {
// error!
}
لاحظ أنه يمكن أن توجد إدخالات متعددة من أنواع مختلفة في نفس خريطة التجزئة. لا تتم كتابة علامة التجزئة - يمكنها تخزين أي بيانات void*
كقيمة للمفتاح.
للحصول على إدخال من hashmap استخدم وظيفة hashmap_get
:
void * const element = hashmap_get ( & hashmap , "x" , strlen ( "x" ));
if ( NULL == element ) {
// error!
}
ستُرجع الدالة NULL
إذا لم يتم العثور على العنصر. لاحظ أن المفتاح المستخدم للحصول على عنصر ليس من الضروري أن يكون هو نفس المؤشر المستخدم لوضع عنصر في خريطة التجزئة - ولكن يجب أن تتطابق شريحة السلسلة حتى تحدث النتيجة.
لإزالة إدخال من hashmap استخدم وظيفة hashmap_remove
:
if ( 0 != hashmap_remove ( & hashmap , "x" , strlen ( "x" ))) {
// error!
}
سترجع الدالة قيمة غير صفرية إذا لم يتم العثور على العنصر. لاحظ أن المفتاح المستخدم للحصول على عنصر ليس من الضروري أن يكون هو نفس المؤشر المستخدم لوضع عنصر في خريطة التجزئة - ولكن يجب أن تتطابق شريحة السلسلة حتى تحدث النتيجة.
يمكنك التكرار على جميع العناصر المخزنة في خريطة التجزئة باستخدام وظيفة hashmap_iterate
:
static int iterate ( void * const context , void * const value ) {
// If the value is 42...
if ( 42 == * ( int * ) value ) {
// Store into our user-provided context the value.
* ( void * * ) context = value ;
// Return 0 to tell the iteration to stop here.
return 0 ;
}
// Otherwise tell the iteration to keep going.
return 1 ;
}
int * value ;
if ( 0 != hashmap_iterate ( & hashmap , iterate , & value )) {
if ( * value != 42 ) {
// error!
}
} else {
// if we got here it means we never found 42 in the hashmap
}
يمكنك الخروج مبكرًا من تكرار علامة التجزئة عن طريق إرجاع قيمة غير صفرية من وظيفة رد الاتصال الخاصة بك - ربما تريد معالجة جميع العناصر من خريطة التجزئة وإزالتها أو البحث عن قيمة محددة فقط. وإلا، إذا تم إرجاع الصفر من رد الاتصال الخاص بك، فسيشمل التكرار علامة التجزئة بأكملها.
في بعض التطبيقات، مثل الحاجة إلى طباعة محتويات خريطة التجزئة، تحتاج إلى الوصول إلى المفتاح وطول المفتاح بالإضافة إلى القيمة. لهذا الغرض تمت إضافة مكرر ثانٍ يسمى hashmap_iterate_pairs
.
كما أن إرجاع -1 من وظيفة رد الاتصال يسمح بالإزالة التلقائية للعنصر الحالي. يعد هذا مفيدًا بشكل خاص عند تخزين الكائنات المخصصة ديناميكيًا على الخريطة والحاجة إلى تحرير الذاكرة عند تدمير الخريطة.
int log_and_free_all ( void * const context , struct hashmap_element_s * const e ) {
int counter ;
for ( counter = 0 ; counter < e -> key_len ; counter ++ ) {
fputc ( e -> key [ counter ], ( FILE ) context );
}
fprintf (( FILE ) context , "=%s pair has been freedn" , ( char * ) e -> data );
free ( e -> data );
return -1 ;
}
void shut_down () {
if ( 0 != hashmap_iterate_pairs ( & hash , log_and_free_all , ( void * ) log )) {
fprintf ( stderr , "failed to deallocate hashmap entriesn" );
}
fclose ( log );
hashmap_destroy ( & hash );
}
للحصول على عدد الإدخالات التي تم وضعها في خريطة التجزئة، استخدم وظيفة hashmap_num_entries
:
unsigned num_entries = hashmap_num_entries ( & hashmap );
للحصول على العدد الفعلي للجرافات المخصصة في الهاشماب (السعة)، استخدم وظيفة hashmap_capacity
:
unsigned num_entries = hashmap_capacity ( & hashmap );
لتدمير خريطة التجزئة عند الانتهاء منها، استخدم وظيفة hashmap_destroy
:
hashmap_destroy ( & hashmap );
تمت كتابة هذا الرمز بالكامل تقريبًا بواسطة Pete Warden الرائع، استنادًا إلى منشور مدونة لم يعد موجودًا الآن بواسطة Elliott Back. قام المؤلفون بتطبيق التغييرات الإضافية التالية:
هذا برنامج مجاني وغير مرتبط تم طرحه في المجال العام.
لأي شخص الحرية في نسخ هذا البرنامج أو تعديله أو نشره أو استخدامه أو تجميعه أو بيعه أو توزيعه، سواء في شكل كود مصدر أو في شكل ثنائي مجمع، لأي غرض، تجاري أو غير تجاري، وبأي وسيلة.
في الولايات القضائية التي تعترف بقوانين حقوق الطبع والنشر، يخصص مؤلف أو مؤلفو هذا البرنامج أي وجميع حقوق الطبع والنشر في البرنامج للملكية العامة. إننا نقوم بهذا التفاني لصالح الجمهور بشكل عام وعلى حساب ورثتنا وخلفائنا. نعتزم أن يكون هذا التفاني بمثابة تنازل صريح إلى الأبد عن جميع الحقوق الحالية والمستقبلية لهذا البرنامج بموجب قانون حقوق الطبع والنشر.
يتم توفير البرنامج "كما هو"، دون أي ضمان من أي نوع، صريحًا أو ضمنيًا، بما في ذلك، على سبيل المثال لا الحصر، ضمانات القابلية للتسويق والملاءمة لغرض معين وعدم الانتهاك. لا يتحمل المؤلفون بأي حال من الأحوال المسؤولية عن أي مطالبة أو أضرار أو مسؤولية أخرى، سواء في إجراء العقد أو الضرر أو غير ذلك، الناشئة عن أو خارج أو فيما يتعلق بالبرنامج أو الاستخدام أو المعاملات الأخرى في البرنامج.
لمزيد من المعلومات، يرجى الرجوع إلى http://unlicense.org/