Bit-masking with OptionSet Swift (in Burmese)
Prerequisite
- Basic knowledge of Swift syntax
What I’ll cover
- Bit Vs Byte
- What is bitmask
- Bitmasking in action
- နိဂုံး
Bit Vs Byte
ကွန်ပျူတာသိပ္ပံဘာသာရပ်ကို သင်ကြားဖူးသူများဖို့တော့ bit နဲ့ byte အကြောင်းက စီကာပတ်ကုံးပြောနေစရာ မလိုလောက်ပါဘူး။ ဒါပေမယ့် မသိသေးသူများလည်း အဆင်ပြေအောင် သိပြီးသူတွေလည်း နည်းနည်းပြန်နွှေးပြီးသားဖြစ်အောင် ဒီအပိုင်းကို ထည့်ထားရတာဖြစ်ပါတယ်။ တစ်ကယ်လို့ သိပြီးသားဆိုရင် ဒီ section တစ်ခုလုံးကို ကျော်ဖတ်လို့ရပါတယ်။
Bit နဲ့ Byte ဆိုတာ data ပမာဏကို တိုင်းတာတဲ့ unit တွေဖြစ်ပါတယ်။ ဉပမာ အလေးချိန်ကို တိုင်းတာမယ်ဆိုရင် ကီလို ပေါင် အောင်စ စသဖြင့် unit တွေရှိပါတယ်။ Data ဆိုတာ သတင်းအချက်အလက် တစ်နည်းပြောရရင် ကွန်ပျူတာက နားလည်တဲ့ သတင်းအချက်အလက်ဖြစ်နေလေတော့ ကွန်ပျူတာနားလည်တဲ့ unit နဲ့ တိုင်းတာရပါတယ်။ ကွန်ပျူတာက ဘာကိုနားလည်သလဲဆိုရင် 0 နဲ့ 1 နှစ်မျိုးပဲနားလည်ပါတယ်။ Bit ဆိုတာ binary digit ကနေလာပါတယ်။ “Bi” ဆိုတာ ၂, “Tri” ဆိုတာ ၃။ Binary digit ဆိုတော့ ကိန်းနှစ်လုံးသာရှိတဲ့ ကိန်းစဉ်တန်းလို့ အဓိပ္ပါယ်ဖွင့်ဆိုနိုင်ပါတယ်။ နောက်တစ်မျိုးပြောရရင် “0” နဲ့ “1” နှစ်ခုထဲက “0” သို့မဟုတ် “1” ကိုသာ ကိုယ်စားပြုနိုင်တဲ့ data ရဲ့ unit ကို bit လို့ခေါ်ပါတယ်။ ကွန်ပျူတာပေါ်မှာ သတင်းအချက်အလက်ပေါင်းများစွာကို bit တွေအနေနဲ့ သိမ်းဆည်းထားပါတယ်။ Bit ရှစ်လုံးပြည့်ရင် 1 Byte နဲ့ ညီမျှပါတယ်။ ဒီတော့ကာ byte တစ်လုံးမှာ 8 bit ပါဝင်ပါတယ်။
အပေါ်က ပုံကိုကြည့်မယ်ဆိုရင် byte တစ်ခုမှာ bit slot ရှစ်လုံးပါဝင်တာကို တွေ့ရပါမယ်။
ဒါကတော့ binary value ကို decimal ပြောင်းတာပါ။ အရင်တုန်းကတော့ အခြေခံပညာသင်္ချာမှာ မြန်မာလို နှစ်လီဆကိန်းစနစ် ဆယ်လီစကိန်းစနစ် ဆယ့်ခြောက်လီစကိန်းစနစ် စသဖြင့် ခေါ်ပါတယ်။ အခုတော့ အဲ့သင်ရိုးရှိသေးလား ပြောင်းသွားပြီလား မသိတော့ပါ။ ပထမဉပမာကို ကြည့်မယ်ဆိုရင် 00000001 က decimal value 1 နဲ့ ညီမျှပါတယ်။ တွက်ပုံတွက်နည်းကတော့ bit slot တစ်ခုချင်းစီကို နောက်ဆုံးကနေစပြီး သက်ဆိုင်ရာ order အလိုက် 2 ပေါ်မှာ ထပ်ကိန်းတင်ပြီး လက်ရှိ time slot ရဲ့ value နဲ့ မြှောက်၊ ရလာတဲ့ တန်ဖိုးအားလုံးကို ပြန်ပေါင်းရတာဖြစ်ပါတယ်။ ပုံကိုကြည့်လိုက်ရင် ပိုရှင်းပါလိမ့်မယ်။
ဒီ article ရဲ့အဓိကအကြောင်းအရာ မဟုတ်တဲ့အတွက် ဒီလောက်သိရင် ရှေ့ဆက်လို့ရလောက်ပါပြီ။ အခြား numbering system တွေအကြောင်းကိုသိချင်ရင်တော့ ကိုယ့်ဘာသာ ရှာဖတ်ကြပါ။
What is bitmask?
Objective-C ဟာ C ကို အခြေခံပါတယ်။ ဒီအတွက်ကြောင့် C language ရဲ့ bit-bashing feature ကို အသုံးပြုနိုင်ပါတယ်။ Swift langauge ဟာ objectvie-c ကိုအခြေခံပါတယ်။ ဉပမာ Swift ရဲ့ Int8 type သည် 8-bit signed integer value တစ်ခုကို ကိုယ်စားပြုပါတယ်။ ရှေ့မှာ ပြောခဲ့သလိုပဲ 0 or 1 နှစ်ခုထဲက တစ်ခုဖြစ်နိုင်တဲ့ slot ရှစ်ခုပါဝင်တဲ့ byte memory slot တစ်ခုကို ကိုယ်စားပြုပါတယ်။
အပေါ်ကလို ရေးလိုက်ရင် a ဆိုတဲ့ variable ဟာ memory ပေါ်မှာ byte တစ်ခုစာ နေရာယူပါတယ်။ အပေါ်ကပြောခဲ့တဲ့နည်းနဲ့တွက်မယ်ဆိုရင် အများဆုံး 2⁰ ကနေ 2⁷ အထိရှိပြီး စုစုပေါင်း 255 ရပါလိမ့်မယ်။ သို့သော် ကျွန်တော်တို့ရဲ့ Int8 သည် signed integer type ဖြစ်တဲ့အတွက် positive ရော negative ရော ဖြစ်နိုင်ပါတယ်။ ဒီအတွက်ကြောင့် -128 ကနေ 127 ကြား value တွေကို သိမ်းဆည်းနိုင်ပါတယ် (-128, -127, …, -2, -1, 0, 1, 2, …, 127)
Bitmask လုပ်တယ်ဆိုတာ variable ‘a’ ရဲ့ value ကို ပြင်တာမဟုတ်ပဲ ‘a’ ထဲမှာရှိတဲ့ bit slot တွေကို 0 or 1 ပြောင်းတာကိုဆိုလိုတာပါ။ ဒီလိုမျိုး bit တစ်ခုကို 1 လို့ပြင်လိုက်တာကို ‘set’ လုပ်တယ်လို့ခေါ်ပြီး 0 ဖြစ်သွားရင်တော့ ‘clear’ လုပ်တယ်လို့ ခေါ်ပါတယ်။ ဒါတွေပြောနေလို့ နားရှုပ်နေနိုင်ပါသေးတယ်။ အဲ့လို bitmask လုပ်လိုက်ရင် ဘာဖြစ်မလဲ ဘာတွေလုပ်လို့ရလဲဆိုတဲ့ usecase နဲ့ပြောပြမှ နားလည်သွားပါလိမ့်မယ်။
ဆိုကြပါစို့ ကျွန်တော်က clinic app တစ်ခုရေးနေတယ်။ လူနာက ဆရာဝန်နဲ့ ပြရမယ့် ရက်တွေကို မှတ်ထားချင်တယ်ဆိုပါစို့။ ဒီနေရာမှာ DaysOfWeek ကို မှတ်လို့ရတဲ့နည်းတွေရှိတယ်။ အလွယ်ဆုံးကတော့ constant ပေါ့။
နောက်တစ်ခါ enum လည်း သုံးလို့ရတာပဲ။
ဒါပေမယ့် အပေါ်က approach နှစ်ခုမှာ memory အပေါ် ဘယ်လောက် bit နေရာယူသွားသလဲဆိုတဲ့ရှုထောင့်ကနေ ကြည့်ကြည့်ရအောင်။ Constant approach မှာဆိုရင် 0, 1 စတာတွေဟာ Int type တွေဖြစ်တယ်။ 32-bit platform မှာဆိုရင် Int32 by default ဖြစ်ပြီးတော့ 64-bit platform မှာဆိုရင် Int64 by default ဖြစ်တယ်။ ဒီနေ့ခေတ်မှာ 32-bit iPhone ဆိုတာ အင်မတန်ရှားသွားပါပြီ။ တစ်လုံးတည်းဆိုရင်မသိသာပေမယ့် “days” လိုကောင်မျိုးမှာဆိုရင် “.sunday” နဲ့ “.tuesday” နှစ်ခုဖြစ်တဲ့အတွက် run နေတဲ့ platform အပေါ်မူတည်ပြီး 32-bit or 64-bit slot နှစ်လုံးစာ memory ပေါ်မှာ နေရာယူသွားပြီ။ Enum လည်း ထိုနည်းလည်းကောင်းပဲ။
အခုလို constant တွေ multiple options တွေကို bit-bashing လုပ်ပြီး variable တစ်လုံးတည်း memeory slot တစ်ခုတည်းပေါ်မှာပဲ သိမ်းထားလို့ရပါတယ်။ ဒီလိုလုပ်တာကို bitmasking လို့ခေါ်ပါတယ်။
အပေါ်က ပုံကိုကြည့်မယ်ဆိုရင် days of week ခုနှစ်မျိုးကို 1 byte (8-bits) တည်းနဲ့ ထိန်းသွားတာကိုတွေ့ရလိမ့်မယ်။ Swift မှာဆိုရင်တော့ Int8 ပေါ့။ ဒါပေမယ့် အဲ့တာကို Int တစ်ခုအဖြစ်မမြင်ဘဲ bit 8 ခုပါတဲ့ memory slot တစ်ခုအနေနဲ့မြင်ကြည့်လိုက်ပါ။ Bit တစ်ခုချင်းစီကို “set” or “clear” လုပ်ပြီး ကြိုက်တဲ့ constant value ကို represent လုပ်သွားလို့ရတယ်။ အပေါ်ကပုံထဲမှာဆိုရင် ဆရာဝန်နဲ့ appointment ယူထားတဲ့ တနင်္လာနဲ့ ဗုဒ္ဓဟူးကို “set” လုပ်ပြီး ကျန်တဲ့ slot တွေကို “clear” လုပ်ပေးထားတာကို တွေ့ရလိမ့်မယ်။
အခုလို Bit manipulation လုပ်တဲ့အခါ အခြေခံအားဖြင့် action လေးမျိုးရှိပါတယ်။ အဲ့တာတွေကတော့
- Shifting
- ORing
- ANDing
- NOTing တို့ပဲဖြစ်ပါတယ်။
ဒီ article မှာ shifting ကိုပဲ ဉီးစားပေးပြီး ပြောပြသွားပါမယ်။ Shifting မှာ left shift နဲ့ right shift ဆိုပြီး နှစ်မျိုးရှိပါတယ်။ Left shift ကို “<<” နဲ့ ရေးရပြီး right shift ကိုတော့ “>>” နဲ့ ရေးရပါတယ်။ အပေါ်ကပုံအရ Monday ကို set လုပ်ဖို့ရာ ဘယ်ဘက်အခြမ်းကို bit တစ်လုံး shift လုပ်ပေးရပါတယ် (1 << 1 results in 00000010) ဒီလိုပဲ Wednesday ကို set လုပ်ဖို့ဆိုရင် (1 << 3) shift လုပ်ပေးရပြီး result အနေနဲ့ 00001000 ဆိုပြီး ထွက်ပါတယ်။ Monday နဲ့ Wednesday နှစ်ခုထဲက တစ်ခုလို့ပြောချင်တဲ့အခါ OR ကိုသုံးရပါတယ်။ OR မှာ (0, 0) → 0, (0, 1) → 1, (1, 1) → 1 ပြန်ထုတ်ပေးပါတယ် (Physics ရဲ့ logic gate တွေအတိုင်းပါပဲ)။ OR ကိုတော့ ‘|’ pipe opeartor နဲ့ ရေးရပါတယ်။ 00000010 | 00001000 လုပ်လိုက်တဲ့အခါ
ဆိုပြီး အပေါ်ကပုံအတိုင်းထွက်လာတာဖြစ်ပါတယ်။ အခုလိုပြောပြရတာက နောက်ကွယ်မှာ ဘယ်လိုအလုပ်လုပ်နေလဲ သိရအောင်ပါ။ တစ်ကယ် code ရေးတဲ့အခါ အဲ့လို calculation တွေက ကိုယ့်ဘာသာလုပ်စရာမလိုပါဘူး။ Bit manipulation က သီးသန့်အကြောင်းအရာတစ်ခုဖြစ်တဲ့အတွက် ဒီလောက်နဲ့ပဲ ရပ်ထားလိုက်ပါမယ်။
ဒီလောက်ဆိုရင်တော့ bitmasking အကြောင်း သဘောပေါက်လောက်ပြီထင်ပါတယ်။ သဘောတရားနားလည်ပြီဆိုရင် code နဲ့ ဘယ်လိုရေးမလဲ ဆက်ကြည့်လိုက်ရအောင်။
Bitmasking in action
ထုံးစံအတိုင်း code အရင်ရေးပြပါမယ်။
- DaystOfWeek ဆိုတဲ့ struct တစ်ခုရေးလိုက်ပါတယ်။ Bitmasking လုပ်ဖို့ရာ OptionSet ဆိုတဲ့ protocol ကို implement လုပ်လိုက်ပါတယ်။
- rawValue ရဲ့ type ကို UInt8 လို့ပေးလိုက်ပါတယ်။ 8-bit unsigned integer ဖြစ်တဲ့အတွက် 0 ကနေ 255 အထိပမာဏကို သိမ်းနိုင်မှာဖြစ်ပါတယ်။ ကျွန်တော်တို့က Days of week ခုနှစ်ခုကိုပဲ represent ချင်တာဖြစ်တဲ့အတွက် more than enough ပါဘဲ။ OptionSet မှာ ဘယ်လို rawValue type တွေသုံးလို့ရလဲဆိုတာကိုတော့ အောက်မှာ ဆက်လက်ဖော်ပြသွားပါမယ်။
- ကျွန်တော်တို့ရဲ့ days of week တွေကို bit-bashing လုပ်ပြီး memory slot တစ်ခုတည်းမှာ သိမ်းထားလိုက်ပါတယ်။
OptionSet တွေကို enum တွေသုံးသလိုပဲ အသုံးပြုနိုင်ပါတယ်။
အပေါ်က weekends နဲ့ weekdays မှာဆိုရင် OptionSet တွေကို | နဲ့ OR လုပ်လိုက်တာဖြစ်ပါတယ်။
01000001 ကို decimal ပြန်ပြောင်းလိုက်ရင် 65 ဆိုပြီးထွက်ပါတယ်။ မယုံရင် weekends ကို print ထုတ်ကြည့်လိုက်ပါ။
ဒါ့အပြင် option set တွေကို insert, remove, union, intersection စသဖြင့် လုပ်လို့ရပါသေးတယ်။
နောက်တစ်ခါ contains ဆိုတာကိုသုံးပြီး ကိုယ်လိုချင်တဲ့ option ရှိမရှိ ရှာလို့ရပါတယ်။
insert နဲ့ union က OR လုပ်တာပါ။ intersection ကတော့ AND လုပ်တာပါ။ remove ကတော့ နာမည်အတိုင်း option set တွေထဲက ကိုယ်ထုတ်ချင်တဲ့ option set ကို ထုတ်တာပါ။ အပေါ်က appointment ထဲကနေ ရှိပြီးသား monday နဲ့ wednesday ကို ထုတ်လိုက်ပါမယ်။ ပြီးရင်တော့ sunday ထည့်လိုက်ပါမယ်။ ဒီလိုဆိုရင်တော့ appointment ထဲမှာ weekdays တွေမရှိတော့ဘဲ weekends တွေပဲရှိတော့တာကို တွေ့ရပါလိမ့်မယ်။
Objective-C မှာဆိုရင်တော့ NS_OPTIONS ဆိုတဲ့ macro ကိုသုံးပြီး bitmask လုပ်လို့ရပါတယ်။ CocoaTouch ရဲ့ options တော်တော်များများဟာ NS_OPTIONS တွေသုံးထားတာကို တွေ့ရပါလိမ့်မယ်။
UIViewAutoresizing option တွေကလည်း တစ်ကယ်တန်းကျတော့ NS_ENUM မဟုတ်ပဲ NS_OPTIONS တွေဖြစ်နေတာကို တွေ့ရမှာပါ။
OptionSet တွေရဲ့ raw value type တွေဟာ FixedWidthInteger protocol ကို implement လုပ်ထားတဲ့ ဘယ် type မဆို လာလို့ရပါတယ်။ Int, Int8, Int16, Int32, Int64 စတာတွေပဲဖြစ်ပါတယ်။ ကိုယ်သုံးချင်တဲ့ constant or options တွေရဲ့ size အပေါ်မူတည်ပြီး efficient ဖြစ်တဲ့ Int size ကိုရွေးချယ်တာကတော့ အကောင်းဆုံးဖြစ်ပါတယ်။ ရှေ့ကဉပမာမှာဆိုရင် option ခုနှစ်ခုပဲရှိတဲ့အတွက် Int8 ကိုပဲ ကျွန်တော်ရွေးချယ်ဖြစ်ခဲ့ပါတယ်။
ဒီနေရာမှာ တစ်ခုမေးစရာရှိတာက enum နဲ့ ဘာကွာသလဲပေါ့။ ဆိုတော့ကာ enum သည် case တွေအများကြီးထဲက case တစ်ခုနဲ့ပဲအလုပ်လုပ်တယ်။ Enum မှာ case နှစ်ခု သုံးခုပေါင်းပြီး အလုပ်လုပ်တယ်ဆိုတာမျိုး မရှိဘူး။ အများဆုံးလုပ်နိုင်ရင် array of enum cases ပုံစံမျိုးနဲ့ပဲရမယ်။ OptionSet ကတော့ case တွေအများကြီးကိုလည်း combine လုပ်ပြီး သုံးလို့ရတယ် (weekends နဲ့ weekdays ကိုကြည့်ပါ)။ ဒါကတော့ enum နဲ့ option set ကြားက အဓိက ကွာခြားချက်ပါ။
Summary
ဒီတစ်ခေါက်မှာတော့ options တွေ constant တွေကို မလိုအပ်ဘဲနဲ့ byte memory တွေ waste မဖြစ်စေပဲ memory slot တစ်ခုတည်းမှာပဲ bit-bashing လုပ်ပြီး ခွဲသိမ်းနိုင်တဲ့ပုံစံကို ပြောပြပေးခဲ့တာပဲဖြစ်ပါတယ်။ ဒီနည်းလမ်းဟာ iPhone 3G, iPhone 4, iPhone 4S ခေတ် iPhone တွေမှာ memory လုံလုံလောက်လောက်မရှိသေးတဲ့အချိန်မှာ app တွေကို efficient ဖြစ်ဖြစ်နဲ့ run နိုင်ဖို့ သုံးခဲ့တဲ့ low-level trick တစ်ခုဖြစ်ပါတယ်။ ဒီနေ့ခေတ်လို memory တွေ ပေါချင်းသောချင်းရနေတဲ့ခေတ်မှာတော့ byte တစ်ခန်းပိုဆောက်မိသွားလည်း အရေးသိပ်မဟုတ်တော့ပေမယ့် သိသင့်သိထိုက်တဲ့ trick တစ်ခုဖြစ်တာကြောင့် article တစ်ပုဒ်အနေနဲ့ ရေးပေးလိုက်ပါတယ်။ အားလုံးပဲ နှစ်သစ်မှာ အရည်အသွေးကောင်းမွန်တဲ့ iOS app တွေကို develop လုပ်နိုင်ပြီး iOS developer ကောင်းတွေ ဖြစ်ကြပါစေဗျား။