مكتبة frozen لـ C++: الدليل الشامل للحاويات في وقت الترجمة
مكتبة frozen هي مكتبة رؤوس فقط (header-only) للغة C++17 والإصدارات الأحدث، توفر حاويات (map, set, string) يتم تهيئتها بالكامل في وقت الترجمة (compile-time). تتيح لك إنشاء هياكل بيانات غير قابلة للتعديل (immutable) لا تحتاج إلى تخصيص ذاكرة ديناميكية أثناء التنفيذ. هذا الحل الأمثل للأنظمة المدمجة، محركات الألعاب، الخوادم عالية التحميل، وأي كود تكون فيه سرعة الأداء وتوقع وقت التنفيذ أمرًا بالغ الأهمية.
الفكرة الأساسية لـ frozen هي أنك تُعرِّف الحاوية على أنها constexpr أو constinit، ويتم تنفيذ جميع عمليات الترتيب والتجزئة وبناء هيكل البيانات أثناء الترجمة. في وقت التشغيل (runtime)، تحصل على حاوية جاهزة ومحسّنة تعمل بأقل تكلفة إضافية. على سبيل المثال، frozen::map تستخدم البحث الثنائي في مصفوفة مرتبة، بينما frozen::unordered_map تستخدم التجزئة المثالية (perfect hashing) مما يضمن وصولاً O(1) بدون تصادمات.
بالنسبة لمطوري C++، هذا يعني: لا ذاكرة ديناميكية (لا new/delete)، لا استثناءات (noexcept)، أمان تام للخيوط (لأن البيانات للقراءة فقط)، وإمكانية وضع الحاويات في ذاكرة الفلاش للمتحكمات الدقيقة. تُستخدم المكتبة بنشاط في مشاريع فيسبوك (ميتا حاليًا)، وفي المترجمات، وفي نوى أنظمة التشغيل.
التثبيت
مكتبة frozen هي مكتبة رؤوس فقط، لذا فإن التثبيت يقتصر على نسخ ملفات الرأس إلى مشروعك. أسهل طريقة هي استخدام Conan أو CMake FetchContent. فيما يلي الأوامر الدقيقة لمختلف مديري الحزم.
التثبيت عبر Conan (موصى به)
conan install frozen/1.1.1@ -r conancenter
# ثم أضف في CMakeLists.txt:
# find_package(frozen REQUIRED)
# target_link_libraries(your_target frozen::frozen)
التثبيت عبر vcpkg
vcpkg install frozen
# بعد التثبيت استخدم:
# find_package(frozen CONFIG REQUIRED)
# target_link_libraries(your_target frozen::frozen)
التثبيت عبر CMake FetchContent (بدون مدير حزم)
include(FetchContent)
FetchContent_Declare(
frozen
GIT_REPOSITORY https://github.com/serge-sans-paille/frozen.git
GIT_TAG v1.1.1
)
FetchContent_MakeAvailable(frozen)
target_link_libraries(your_target frozen::frozen)
التثبيت اليدوي (رؤوس فقط)
git clone https://github.com/serge-sans-paille/frozen.git
# انسخ مجلد frozen/include/frozen إلى مشروعك
# أضف المسار إلى include في المترجم:
# g++ -I/path/to/frozen/include your_file.cpp -std=c++17
بداية سريعة: مثال عملي مصغر
أنشئ ملفًا باسم example.cpp بالمحتوى التالي:
#include <iostream>
#include <frozen/unordered_map.h>
#include <frozen/string.h>
int main() {
// إنشاء خريطة في وقت الترجمة بتجزئة مثالية
constexpr frozen::unordered_map<frozen::string, int, 3> سعرات_الفواكه = {
{"تفاح", 95},
{"موز", 105},
{"برتقال", 62}
};
// بحث في وقت التشغيل — O(1)، بدون تصادمات
std::cout << "سعرات الموز: " << سعرات_الفواكه.at("موز") << "\n";
// التحقق من وجود مفتاح
if (auto it = سعرات_الفواكه.find("عنب"); it != سعرات_الفواكه.end()) {
std::cout << "العنب موجود: " << it->second << "\n";
} else {
std::cout << "العنب غير موجود\n";
}
// التكرار على جميع العناصر
for (auto& [فاكهة, سعرات] : سعرات_الفواكه) {
std::cout << فاكهة.data() << ": " << سعرات << " سعرة حرارية\n";
}
return 0;
}
قم بتجميع البرنامج باستخدام الأمر التالي:
g++ -std=c++17 -I/path/to/frozen/include example.cpp -o example
./example
النتيجة المتوقعة:
سعرات الموز: 105
العنب غير موجود
تفاح: 95 سعرة حرارية
موز: 105 سعرة حرارية
برتقال: 62 سعرة حرارية
الدوال الأساسية في frozen
تقدم المكتبة عدة حاويات رئيسية. إليك أهمها مع شرح مختصر:
frozen::map
خريطة مرتبة تعتمد على البحث الثنائي في مصفوفة ثابتة. مثالية للبيانات التي تحتاج إلى ترتيب.
constexpr frozen::map<int, const char*, 3> my_map = {{1, "واحد"}, {2, "اثنان"}, {3, "ثلاثة"}};
auto it = my_map.find(2); // إرجاع مكرر (iterator) يشير إلى {2, "اثنان"}
frozen::unordered_map
خريطة غير مرتبة تستخدم التجزئة المثالية. توفر وصولاً O(1) بدون تصادمات.
constexpr frozen::unordered_map<int, double, 4> prices = {{1, 10.5}, {2, 20.3}, {3, 15.8}, {4, 7.2}};
double price = prices.at(3); // 15.8
frozen::set
مجموعة مرتبة من العناصر الفريدة.
constexpr frozen::set<int, 5> numbers = {10, 20, 30, 40, 50};
bool found = numbers.count(30); // true
frozen::unordered_set
مجموعة غير مرتبة بتجزئة مثالية.
constexpr frozen::unordered_set<int, 4> ids = {100, 200, 300, 400};
auto it = ids.find(200); // مكرر يشير إلى 200
frozen::string
سلسلة نصية ثابتة في وقت الترجمة.
constexpr frozen::string hello = "مرحبا بالعالم";
std::cout << hello.data() << "\n"; // طباعة: مرحبا بالعالم
نصائح وحيل للمطورين المحترفين
- استخدم constexpr كلما أمكن: تأكد من أن الحاوية معرفة كـ
constexprلضمان التهيئة في وقت الترجمة. - اختر الحاوية المناسبة: استخدم
frozen::mapإذا كنت بحاجة إلى ترتيب، وfrozen::unordered_mapإذا كانت سرعة الوصول هي الأولوية. - تجنب الأحجام الكبيرة جدًا: على الرغم من أن frozen محسّنة، إلا أن الحاويات الكبيرة جدًا قد تزيد من وقت الترجمة.
- استخدم frozen::string بدلاً من const char*: frozen::string توفر مقارنة أسرع في وقت الترجمة.
- للاستخدام في الأنظمة المدمجة: يمكن وضع الحاويات في ذاكرة القراءة فقط (ROM/Flash) باستخدام
constinit.
الخلاصة
مكتبة frozen هي أداة قوية لأي مطور C++ يريد تحسين أداء تطبيقاته من خلال نقل العمل إلى وقت الترجمة. سواء كنت تعمل على أنظمة مدمجة، ألعاب، أو خوادم عالية الأداء، فإن frozen توفر لك حاويات سريعة وآمنة وخالية من التخصيص الديناميكي. ابدأ باستخدامها اليوم واستمتع بكتابة كود C++ أكثر كفاءة وثباتًا!