נתונים באורך קבוע

vec#

קריאה או כתיבה של חריץ ברוחב קבוע בתוך מחרוזת המטופלת כווקטור ביטים ארוז.

vec רואה את EXPR כמערך של מספרים שלמים חסרי־סימן, כל אחד ברוחב BITS, ארוזים גב־אל־גב מתחילת המחרוזת. OFFSET מאנדקס לתוך אותו מערך - לא לתוך בתים, לא לתוך ביטים, אלא לתוך אלמנטים בגודל BITS. צורת הקריאה מחזירה את המספר השלם באותו חריץ; צורת ה־lvalue כותבת אחד. הרוחבים הם 1, 2, 4, 8, 16, 32, ובמהדורות 64־ביט גם 64.

תקציר#

my $n = vec($buf, $offset, $bits);
vec($buf, $offset, $bits) = $n;

מה מקבלים בחזרה#

בהקשר rvalue, מספר שלם חסר־סימן - תוכן החריץ הנבחר, מורחב באפסים למספר Perl. בהקשר lvalue, חריץ הניתן להשמה; השמה חותכת את הערך הימני ל־BITS וכותבת אותו לתוך המחרוזת, מרחיבה את המחרוזת בבתי אפס אם OFFSET חורג מהסוף הנוכחי.

הסוגריים סביב vec(...) בצורת ה־lvalue נדרשים - בלעדיהם, vec $buf, $o, $b = 3 מפרסר את ה־= כחלק מרשימת הארגומנטים.

כיצד הביטים מסודרים#

הפריסה תלויה ב־BITS, ונבחרת כך שהקוד יהיה נייד בין מכונות big-endian ו־little-endian:

  • BITS == 8: כל חריץ הוא בית אחד של המחרוזת. vec($s, $i, 8) הוא הערך חסר־הסימן של substr($s, $i, 1).

  • BITS == 16, 32, 64: בתי המחרוזת מקובצים לחלקים של BITS/8 ומפורשים בסדר big-endian - שווה־ערך ל־unpack עם n, N, או (במהדורות 64־ביט) Q> / המקבילה המוסרית. vec($s, 0, 32) קורא את ארבעת הבתים הראשונים כ־uint32 big-endian.

  • BITS == 4, 2, 1: המחרוזת מפורקת לבתים, וכל בית מפוצל לקבוצות של 8/BITS, ממוספרות בסדר דמוי־little-endian בתוך הבית. ערכי הביטים מהנמוך לגבוה הם 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80. אז עבור chr(0x36) (0b00110110):

    • BITS == 4 נותן את שני ה־nibbles (0x6, 0x3).

    • BITS == 2 נותן את ארבע קבוצות הדו־ביט (0x2, 0x1, 0x3, 0x0).

    • BITS == 1 נותן את שמונת הביטים (0, 1, 1, 0, 1, 1, 0, 0).

חריץ הנמצא כולו מחוץ לסוף המחרוזת נקרא כ־0. כתיבה מעבר לסוף מגדילה את המחרוזת בבתי אפס כדי להגיע לחריץ. OFFSET שלילי הוא שגיאה קטלנית.

מצב גלובלי שהוא נוגע בו#

אין. vec פועל אך ורק על הארגומנטים שלו.

דוגמאות#

קריאת בית באינדקס נתון:

my $s = "Perl";
print vec($s, 0, 8);            # 80   (== ord 'P')
print vec($s, 3, 8);            # 108  (== ord 'l')

בניית מחרוזת על־ידי כתיבת מילים big-endian של 32־ביט:

my $buf = '';
vec($buf, 0, 32) = 0x5065726C;  # "Perl"
vec($buf, 1, 32) = 0x50657270;  # "PerlPerp"
print $buf;                     # PerlPerp

שימוש ב־vec כמערך בוליאני קומפקטי - ביט אחד לכל דגל:

my $flags = '';
vec($flags, 17, 1) = 1;
vec($flags, 42, 1) = 1;
print vec($flags, 17, 1);       # 1
print vec($flags, 18, 1);       # 0  (slot never set, still zero)
print length $flags;            # 6  (string auto-extended to fit bit 42)

ספירת הביטים הקבועים בווקטור ביטים בלי לעבור ביט־ביט בלולאה - התבנית האידיומטית משתמשת ב־unpack:

my $ones = unpack("%32b*", $flags);   # population count

המרת ווקטור ביטים למחרוזת של 0־ים ו־1־ים להצגה:

my $bits = unpack("b*", $flags);      # "00...010...010..."

שילוב שני ווקטורי ביטים עם אופרטורי המחרוזת הביטיים - אלה מטפלים באופרנדי מחרוזת כווקטורי ביטים באותה צורה ש־vec קורא וכותב:

my $union        = $flags_a | $flags_b;
my $intersection = $flags_a & $flags_b;
my $diff         = $flags_a ^ $flags_b;

מקרי קצה#

  • קדימות lvalue: vec EXPR, O, B = N היא שגיאת תחביר. יש לכתוב תמיד vec(EXPR, O, B) = N.

  • קריאה מחוץ לסוף: vec($short, 1_000_000, 8) מחזיר 0, לעולם אינו מת, לעולם אינו מזהיר.

  • כתיבה מחוץ לסוף: המחרוזת מרופדת באפסים עד לחריץ. עבור BITS == 1, כתיבת ביט 94 מגדילה את המחרוזת ל־12 בתים.

  • OFFSET שלילי: קטלני - "Negative offset to vec in lvalue context" או המקבילה ב־rvalue.

  • BITS אינו חזקת שתיים נתמכת: קטלני עם "Illegal number of bits in vec". הרוחבים התקפים הם 1, 2, 4, 8, 16, 32, ו־64 במהדורות 64־ביט.

  • מחרוזות מקודדות UTF-8: vec רוצה מחרוזת בתים. אם הסקלר מתויג UTF-8, Perl מנסה תחילה להוריד אותו לייצוג של בית־אחד־לכל־תו. אם לתו כלשהו יש נקודת קוד של 256 או יותר, הדבר נכשל קטלנית עם "Wide character in vec". יש לקרוא ל־utf8::downgrade במכוון, או לארוז את הנתונים עם pack "C*" תחילה, לפני שפונים ל־vec.

  • קריאה על undef: תחת use warnings, מפעיל אזהרת uninitialized על ארגומנט המחרוזת; מחזיר 0.

  • ערך השמה רחב מ־BITS: הערך ממוסך לביטים הנמוכים של BITS. vec($s, 0, 4) = 0x1F מאחסן 0xF.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • pack - לבנות מבני בינארי רבי־שדות; vec הוא המקבילה לגישה רנדומלית כאשר לכל שדה יש אותו רוחב

  • unpack - לשלוף שדות ממחרוזת בינארית; יש להשתמש ב־unpack("b*", $v) או unpack("%32b*", $v) כדי להציג או לעשות popcount לווקטור ביטים של vec

  • substr - גישה רנדומלית ברמת הבית כאשר BITS היה 8 ורוצים גם של־lvalue יגדיל או יקטין את המחרוזת

  • sprintf - לעצב את המספר השלם שקריאת vec מחזירה, למשל sprintf "%08b", vec($s, $i, 8)

  • ord - שווה־ערך חד־פעמי ל־vec($s, $i, 8) כאשר נדרש רק ערך הבית ולעולם אין השמה חזרה