توفر مكتبة الخرائط المرتبة خريطة تجزئة ومجموعة تجزئة تحافظ على ترتيب الإدراج بطريقة مشابهة لـ OrderedDict في Python. عند التكرار على الخريطة، سيتم إرجاع القيم بنفس الترتيب الذي تم إدراجها به.
يتم تخزين القيم بشكل متجاور في البنية الأساسية، ولا توجد فجوات بين القيم حتى بعد عملية المسح. بشكل افتراضي، يتم استخدام std::deque
لهذه البنية، ولكن من الممكن أيضًا استخدام std::vector
. يمكن الوصول إلى هذه البنية مباشرة من خلال طريقة values_container()
وإذا كانت البنية std::vector
، فسيتم أيضًا توفير طريقة data()
للتفاعل بسهولة مع واجهات برمجة التطبيقات C. يوفر هذا تكرارًا سريعًا ولكن مع عيب عملية المسح O(bucket_count). تتوفر الدالتان O(1) pop_back()
وO(1) unordered_erase()
. إذا تم استخدام المسح المطلوب في كثير من الأحيان، فمن المستحسن بنية بيانات أخرى.
لحل التصادمات على التجزئة، تستخدم المكتبة فحص روبن الخطي مع حذف التحول إلى الخلف.
توفر المكتبة سلوكًا مشابهًا للمتجه std::deque/std::vector
بقيم فريدة ولكن بمتوسط تعقيد زمني يبلغ O(1) لعمليات البحث وتعقيد زمني مستهلك قدره O(1) لعمليات الإدراج. يأتي هذا على حساب مساحة ذاكرة أعلى قليلاً (8 بايت لكل مجموعة افتراضيًا).
يتم توفير فئتين: tsl::ordered_map
و tsl::ordered_set
.
ملاحظة : تستخدم المكتبة قوة اثنين لحجم مصفوفة الدلاء الخاصة بها للاستفادة من المعامل السريع. للحصول على أداء جيد، يتطلب الأمر أن يكون لجدول التجزئة وظيفة تجزئة موزعة بشكل جيد. إذا واجهت مشكلات في الأداء، فتحقق من وظيفة التجزئة لديك.
tsl::ordered_map
من CMakeLists.txt.std::unordered_map
ولكن مع عمليات إدراج أسرع واستخدام أقل للذاكرة (راجع المعيار لمزيد من التفاصيل).find
بنوع مختلف عن Key
(على سبيل المثال، إذا كان لديك خريطة تستخدم std::unique_ptr<foo>
كمفتاح، فيمكنك استخدام foo*
أو std::uintptr_t
كمعلمة رئيسية لـ find
دون إنشاء std::unique_ptr<foo>
، انظر المثال).precalculated_hash
في API).serialize/deserialize
في واجهة برمجة التطبيقات للحصول على التفاصيل).-fno-exceptions
في Clang وGC، بدون خيار /EH
على MSVC أو ببساطة عن طريق تحديد TSL_NO_EXCEPTIONS
). يتم استخدام std::terminate
لاستبدال تعليمات throw
عند تعطيل الاستثناءات.std::unordered_map
و std::unordered_set
.std::unordered_map
يحاول tsl::ordered_map
الحصول على واجهة مشابهة لـ std::unordered_map
ولكن توجد بعض الاختلافات.
RandomAccessIterator
.std::vector
و std::deque
(راجع واجهة برمجة التطبيقات لمزيد من التفاصيل). إذا كنت تستخدم std::vector
كـ ValueTypeContainer
، فيمكنك استخدام reserve()
لتخصيص بعض المساحة مسبقًا وتجنب إبطال المكررات عند الإدراج.erase()
لها تعقيد O (bucket_count). يوجد إصدار أسرع من O(1) unordered_erase()
، ولكنه يكسر ترتيب الإدراج (راجع واجهة برمجة التطبيقات لمزيد من التفاصيل). يتوفر أيضًا O(1) pop_back()
.operator==
operator!=
يعتمدان على الترتيب. لا يمكن مقارنة اثنين من tsl::ordered_map
بنفس القيم ولكن تم إدراجهما بترتيب مختلف.operator*()
operator->()
بإرجاع مرجع ومؤشر إلى const std::pair<Key, T>
بدلاً من std::pair<const Key, T>
مما يجعل القيمة T
غير قابلة للتعديل. لتعديل القيمة عليك استدعاء طريقة value()
للمكرر للحصول على مرجع قابل للتغيير. مثال: tsl::ordered_map< int , int > map = {{ 1 , 1 }, { 2 , 1 }, { 3 , 1 }};
for ( auto it = map.begin(); it != map.end(); ++it) {
// it->second = 2; // Illegal
it. value () = 2 ; // Ok
}
IndexType
، تحقق من واجهة برمجة التطبيقات للحصول على التفاصيل.bucket_size
، bucket
، ...). ضمان سلامة سلسلة الرسائل هو نفسه std::unordered_map
(أي من الممكن أن يكون لديك عدة قراء متزامنين بدون كاتب).
تنطبق هذه الاختلافات أيضًا بين std::unordered_set
و tsl::ordered_set
.
إذا لم يتم ذكر خلاف ذلك، تتمتع الوظائف بضمان الاستثناء القوي، راجع التفاصيل. ندرج أدناه الحالات التي لا يتم فيها توفير هذا الضمان.
يتم توفير الضمان فقط إذا كانت ValueContainer::emplace_back
تتمتع بضمان الاستثناء القوي (وهو ما ينطبق على std::vector
و std::deque
طالما أن النوع T
ليس من النوع القابل للتحريك فقط مع مُنشئ النقل الذي قد يرمي استثناء، انظر التفاصيل).
تتمتع وظائف tsl::ordered_map::erase_if
و tsl::ordered_set::erase_if
بالضمان فقط بموجب الشروط المسبقة المدرجة في وثائقها.
لاستخدام الخريطة المرتبة، ما عليك سوى إضافة دليل التضمين إلى مسار التضمين الخاص بك. إنها مكتبة رأسية فقط .
إذا كنت تستخدم CMake، فيمكنك أيضًا استخدام الهدف المُصدَّر tsl::ordered_map
من CMakeLists.txt مع target_link_libraries
.
# Example where the ordered-map project is stored in a third-party directory
add_subdirectory (third-party/ordered-map)
target_link_libraries (your_target PRIVATE tsl::ordered_map)
إذا تم تثبيت المشروع من خلال make install
، فيمكنك أيضًا استخدام find_package(tsl-ordered-map REQUIRED)
بدلاً من add_subdirectory
.
يجب أن تعمل التعليمات البرمجية مع أي مترجم متوافق مع معيار C++ 11 وقد تم اختبارها مع دول مجلس التعاون الخليجي 4.8.4، Clang 3.5.0 وVisual Studio 2015.
لإجراء الاختبارات، ستحتاج إلى مكتبة Boost Test وCMake.
git clone https://github.com/Tessil/ordered-map.git
cd ordered-map/tests
mkdir build
cd build
cmake ..
cmake --build .
./tsl_ordered_map_tests
يمكن العثور على واجهة برمجة التطبيقات هنا.
# include < iostream >
# include < string >
# include < cstdlib >
# include < tsl/ordered_map.h >
# include < tsl/ordered_set.h >
int main () {
tsl::ordered_map< char , int > map = {{ ' d ' , 1 }, { ' a ' , 2 }, { ' g ' , 3 }};
map. insert ({ ' b ' , 4 });
map[ ' h ' ] = 5 ;
map[ ' e ' ] = 6 ;
map. erase ( ' a ' );
// {d, 1} {g, 3} {b, 4} {h, 5} {e, 6}
for ( const auto & key_value : map) {
std::cout << " { " << key_value. first << " , " << key_value. second << " } " << std::endl;
}
map. unordered_erase ( ' b ' );
// Break order: {d, 1} {g, 3} {e, 6} {h, 5}
for ( const auto & key_value : map) {
std::cout << " { " << key_value. first << " , " << key_value. second << " } " << std::endl;
}
for ( auto it = map. begin (); it != map. end (); ++it) {
// it->second += 2; // Not valid.
it. value () += 2 ;
}
if (map. find ( ' d ' ) != map. end ()) {
std::cout << " Found 'd'. " << std::endl;
}
const std:: size_t precalculated_hash = std::hash< char >()( ' d ' );
// If we already know the hash beforehand, we can pass it as argument to speed-up the lookup.
if (map. find ( ' d ' , precalculated_hash) != map. end ()) {
std::cout << " Found 'd' with hash " << precalculated_hash << " . " << std::endl;
}
tsl::ordered_set< char , std::hash< char >, std::equal_to< char >,
std::allocator< char >, std::vector< char >> set;
set. reserve ( 6 );
set = { ' 3 ' , ' 4 ' , ' 9 ' , ' 2 ' };
set. erase ( ' 2 ' );
set. insert ( ' 1 ' );
set. insert ( '