2015-10-07 3 views
3

У меня очень большая структура, которую я хочу обеспечить, не копируется бесполезно. Как я могу создать для него контейнер для копирования?Как я могу создать контейнер с семантикой copy-on-write? (Swift)

+0

Какая у вас крупная структура? Я спрашиваю, потому что Свифт уже выполняет (часть) работу за вас. См. Http://stackoverflow.com/questions/26593992/when-does-the-copying-take-place-for-swift-value-types – courteouselk

+0

@ Антон Бронников: Я знаю об этих оптимизациях. Этот вопрос должен был стать учебным учебным курсом Q/A. –

+0

Я понимаю. Вот почему я спрашиваю о такой большой структуре, для которой это предназначено. Тот факт, что такой образовательный Q/A существует, указывает на необходимость его использования (например, что, если не все случаи использования покрываются оптимизацией Swift-компилятора?). Это могло бы только улучшить ситуацию, если бы вы могли упомянуть о применимых случаях использования, так как иначе это было бы пустой тратой усилий на то, чтобы делать/поддерживать то, что Свифт сделает для вас в любом случае и без каких-либо затрат. – courteouselk

ответ

6

Копирование-на-запись обычно является оберткой struct над некоторым вспомогательным объектом.

public final class MutableHeapStore<T>: NonObjectiveCBase 
{ 
    public typealias Storage = T 

    public private(set) var storage: Storage 

    public init(storage: Storage) 
    { 
     self.storage = storage 
    } 
} 

public struct COW<T> 
{ 
    public typealias Storage = MutableHeapStore<T> 
    public typealias Value = T 

    public var storage: Storage 

    public init(storage: Storage) 
    { 
     self.storage = storage 
    } 

    public var value: Value 
    { 
     get 
     { 
      return storage.storage 
     } 

     set 
     { 
      if isUniquelyReferenced(&storage) 
      { 
       storage.storage = newValue 
      } 

      else 
      { 
       storage = Storage(storage: newValue) 
      } 
     } 
    } 

    public init(_ value: Value) 
    { 
     self.init(storage: Storage(storage: value)) 
    } 
} 

extension COW: CustomStringConvertible 
{ 
    public var description: String 
    { 
     return String(value) 
    } 
} 

Хитрость заключается в утверждении isUniquelyReferenced каждый раз, когда коробочное значение мутировавшие. Если основной объект хранилища указывается отдельно, ничего не нужно делать. Однако, если существует другая ссылка, необходимо создать новое хранилище.

Этот код безопасен? Это точно так же безопасно, как и любой другой тип значения, например. Int или Bool.

+0

похоже, что код в 'isUniquelyReferenced' никогда не был запущен, я добавляю инструкцию печати внутри, никогда не получаю вывод – dispute

1

Вот несколько более простой пример.

struct COWExample1<T> { 
    private var box = Box<[T]>(value: [T]()) 
    var count: Int { 
     return box.value.count 
    } 
    mutating func append(e: T) { 
     ensureBoxUniqueRefed() 
     box.value.append(e) 
    } 
    private mutating func ensureBoxUniqueRefed() { 
     if isUniquelyReferencedNonObjC(&box) == false { 
      box = box.duplicated() 
     } 
    } 
} 

private final class Box<T> { 
    var value: T 
    init(value: T) { 
     self.value = value 
    } 
    func duplicated() -> Box<T> { 
     return Box(value: value) 
    } 
} 
1

Предыдущие ответы не ошибаются, но есть гораздо более простой способ. Swift команда a list of performance tips, и они говорят:

Самый простой способ осуществить копирование при записи, чтобы составить существующие копии при записи структуры данных, такие как массив.

Это не намного проще!

+0

Хороший совет, особенно для новичков. –

+0

Не только для новичков - этот документ специально говорит: «Предполагаемая аудитория этого документа - это компилятор и разработчики стандартной библиотеки». – Ssswift

 Смежные вопросы

  • Нет связанных вопросов^_^