Last active
August 20, 2021 04:02
-
-
Save HevaWu/40bad4ca94beb7a2a60e8c1f98c6470a to your computer and use it in GitHub Desktop.
Swift Option Compare: OptionSet vs Enum vs Struct
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func log(_ category: LCategory) { | |
print(category.description) | |
} | |
log(.categoryA) | |
log([.categoryB, .categoryA]) | |
log([.categoryA, .categoryB]) | |
struct LCategory: OptionSet, CustomStringConvertible { | |
let rawValue: Int | |
static let categoryA = LCategory(rawValue: 1 << 0) | |
static let categoryB = LCategory(rawValue: 1 << 1) | |
static let categoryC = LCategory(rawValue: 1 << 2) | |
static let categoryD = LCategory(rawValue: 1 << 3) | |
static let categoryE = LCategory(rawValue: 1 << 4) | |
static var descriptionMap: [Int: String] = [ | |
LCategory.categoryA.rawValue: "categoryA", | |
LCategory.categoryB.rawValue: "categoryB", | |
LCategory.categoryC.rawValue: "categoryC", | |
LCategory.categoryD.rawValue: "categoryD", | |
LCategory.categoryE.rawValue: "categoryE", | |
] | |
var description: String { | |
var valList = [String]() | |
for k in getOptionList() { | |
if let val = Self.descriptionMap[k] { | |
valList.append(val) | |
} else { | |
assertionFailure("LCategory descriptionMap not contains key \(k)") | |
} | |
} | |
var str = String("[") | |
str.append(contentsOf: valList.joined(separator: "][")) | |
str.append("]") | |
return str | |
} | |
func getOptionList() -> [Int] { | |
var list = [Int]() | |
let largest = rawValue.bitWidth - rawValue.leadingZeroBitCount | |
for i in 0..<largest { | |
if rawValue & (1 << i) != 0 { | |
list.append(1 << i) | |
} | |
} | |
return list | |
} | |
} | |
extension LCategory { | |
static let categoryZ = LCategory(rawValue: 1 << 25) | |
} | |
LCategory.descriptionMap[LCategory.categoryZ.rawValue] = "categoryZ" | |
log([.categoryZ, .categoryA, .categoryB]) | |
// ========= LCategoryType protocol ============================================== | |
protocol LCategoryType: OptionSet, CustomStringConvertible { | |
var rawValue: Int { get set } | |
static var descriptionMap: [Int: String] { get set } | |
} | |
extension LCategoryType { | |
var description: String { | |
var valList = [String]() | |
for k in getOptionList() { | |
if let val = Self.descriptionMap[k] { | |
valList.append(val) | |
} else { | |
assertionFailure("LCategory descriptionMap not contains key \(k)") | |
} | |
} | |
var str = String("[") | |
str.append(contentsOf: valList.joined(separator: "][")) | |
str.append("]") | |
return str | |
} | |
func getOptionList() -> [Int] { | |
var list = [Int]() | |
let largest = rawValue.bitWidth - rawValue.leadingZeroBitCount | |
for i in 0..<largest { | |
if rawValue & (1 << i) != 0 { | |
list.append(1 << i) | |
} | |
} | |
return list | |
} | |
} | |
struct LCategoryTest: LCategoryType { | |
var rawValue: Int | |
static let categoryA = LCategoryTest(rawValue: 1 << 0) | |
static let categoryB = LCategoryTest(rawValue: 1 << 1) | |
static var descriptionMap: [Int : String] = [ | |
LCategoryTest.categoryA.rawValue: "categoryA", | |
LCategoryTest.categoryB.rawValue: "categoryB" | |
] | |
} | |
func log(_ category: LCategoryType) { | |
print(category.description) | |
} | |
// ========= LCategoryType protocol Others ================================ | |
//protocol LCategory: CustomStringConvertible { | |
// associatedtype T: CustomStringConvertible | |
// var type: T { get set } | |
//} | |
// | |
//extension LCategory { | |
// var description: String { | |
// return type.description | |
// } | |
//} | |
//class LCategoryType: OptionSet { | |
// | |
// let rawValue: Int | |
// | |
// required init(rawValue: Int) { | |
// self.rawValue = rawValue | |
// } | |
// | |
// func getDescriptionMap() -> [Int: String] { | |
// fatalError("Must implement getDescriptionMap function in sub-class") | |
// } | |
// | |
// func getDescription() -> String { | |
// fatalError("Must implement getDescription function in sub-class") | |
// } | |
// | |
// func getOptionList() -> [Int] { | |
// var list = [Int]() | |
// let largest = rawValue.bitWidth - rawValue.leadingZeroBitCount | |
// for i in 0..<largest { | |
// if rawValue & (1 << i) != 0 { | |
// list.append(1 << i) | |
// } | |
// } | |
// return list | |
// } | |
// | |
//} | |
//class LCategoryModule: LCategoryType { | |
// | |
// static let categoryA = LCategoryModule(rawValue: 1 << 0) | |
// static let categoryB = LCategoryModule(rawValue: 1 << 1) | |
// static let categoryC = LCategoryModule(rawValue: 1 << 2) | |
// static let categoryD = LCategoryModule(rawValue: 1 << 3) | |
// static let categoryE = LCategoryModule(rawValue: 1 << 4) | |
// | |
// required init(rawValue: Int) { | |
// super.init(rawValue: rawValue) | |
// } | |
// | |
// override func getDescriptionMap() -> [Int: String] { | |
// | |
// return [ | |
// LCategoryModule.categoryA.rawValue: "categoryA", | |
// LCategoryModule.categoryB.rawValue: "categoryB", | |
// LCategoryModule.categoryC.rawValue: "categoryC", | |
// LCategoryModule.categoryD.rawValue: "categoryD", | |
// LCategoryModule.categoryE.rawValue: "categoryE", | |
// ] | |
// } | |
// | |
// override func getDescription() -> String { | |
// var valList = [String]() | |
// let map = getDescriptionMap() | |
// for k in getOptionList() { | |
// if let val = map[k] { | |
// valList.append(val) | |
// } else { | |
// assertionFailure("LCategory descriptionMap not contains key \(k)") | |
// } | |
// } | |
// var str = String("[") | |
// str.append(contentsOf: valList.joined(separator: "][")) | |
// str.append("]") | |
// return str | |
// } | |
//} | |
// | |
////extension LCategory { | |
//// static let categoryZ = LCSLoggerCategory(rawValue: 1 << 26) | |
////} | |
// | |
//let d: LCategoryType = [LCategoryModule.categoryA, LCategoryModule.categoryZ] | |
//print(d.description) | |
// ========= Enum ============================================== | |
enum LCategory: String { | |
case categoryA | |
case categoryB | |
case categoryC | |
} | |
extension LCategory { | |
case categoryD | |
} | |
// ========= struct ============================================== | |
struct LCategory: CustomStringConvertible { | |
private let typeList: [LCategoryType] | |
init(_ category: LCategoryType) { | |
typeList = [category] | |
} | |
init(_ cateogories: [LCategoryType]) { | |
typeList = cateogories | |
} | |
var description: String { | |
let sortedList = typeList.sorted().map { $0.rawValue } | |
var str = String() | |
str.append("[") | |
str.append(sortedList.joined(separator: "][")) | |
str.append("]") | |
return str | |
} | |
} | |
struct LCategoryType { | |
let rawValue: String | |
static let categoryA = LCategoryType(rawValue: "categoryA") | |
static let categoryB = LCategoryType(rawValue: "categoryB") | |
static let categoryC = LCategoryType(rawValue: "categoryC") | |
static let categoryD = LCategoryType(rawValue: "categoryD") | |
} | |
extension LCategoryType: Comparable { | |
static func < (lhs: LCategoryType, rhs: LCategoryType) -> Bool { | |
return lhs.rawValue < rhs.rawValue | |
} | |
} | |
extension LCategoryType { | |
static let categoryF = LCategoryType(rawValue: "categoryF") | |
} | |
func log(category: LCategory) { | |
print(category.description) | |
} | |
log(category: .init([.categoryF, .categoryA, .categoryB])) | |
log(category: .init(.categoryA)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Blog: https://hevawu.github.io/blog/2021/08/20/Define-Your-Own-Option-OptionSet-vs-Enum-vs-struct