Même avec Swift, horodatage en nanosecondes!

Les horodatages en nanosecondes sont faciles.

Oui, en langage C. Cependant, le nom de la fonction est différent de clock_gettime () sous Linux et de clock_get_time () sous OS X. Le nom de la structure qui représente le temps en nanosecondes est également différent. La procédure d'obtention d'un horodatage à l'aide de cette structure est également différente. Swift peut utiliser les fonctions du langage C, et Swift est maintenant disponible sur Linux et OS X, absorbons donc cette différence avec Swift.

emballer

J'ai essayé de le faire. Et publié sur GitHub. C'est une licence MIT.

Code source

Il n'y a qu'un seul fichier. J'ai essayé de nommer le fichier TimeSpecification.swift. Et j'ai essayé de nommer la structure dans Swift "Time Specification". Les seules propriétés (propriété stockée) sont "secondes" et "nanosecondes". Ce qui suit est un extrait et une explication. L'ordre des explications et l'ordre du code dans le source ne correspondent pas toujours, alors n'ayez pas peur ... Je n'ai rien fait de difficile. Je ne peux pas dire ça.

Un sort qui absorbe la différence d'OS

ʻImportpour que les bibliothèques standard spécifiques au système d'exploitation puissent être utilisées.Glibc pour Linux, Darwinpour OS X. Le temps de la nanoseconde est représenté parstruct timespec sous Linux et mach_timespec_t ( typedef struct mach_timespec mach_timespec_t; ) sous OS X. Dans les deux cas, les secondes sont représentées par le membre «.tv_sec» et les nanosecondes sont représentées par le membre «.tv_nsec». Cependant, .tv_sec est time_t dans struct timespec, mais ʻunsigned int [^ tv_sec_unsigned_int] dans mach_timespec_t, et .tv_nsec est long et clock_res_t (typedef int clock_res_t; ) Mais le contenu est complètement différent. Alors, nommons les deux CTimeSpec une fois avec typealias.

[^ tv_sec_unsigned_int]: 2106 issue est susceptible de se produire

#if os(Linux)
  import Glibc
  private typealias CTimeSpec = timespec
#elseif os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
  import Darwin
  private let mach_task_self:() -> mach_port_t = { return mach_task_self_ }
  private typealias CTimeSpec = mach_timespec_t
#else
  // UNKNOWN OS
#endif

L'initialisation de la «Spécification de l'heure» avec la «Spécification de l'heure C» est facile. Ce que vous pouvez faire car les membres ont le même nom à la fois dans struct timespec et mach_timespec_t:

extension TimeSpecification {
  fileprivate init(_ cts:CTimeSpec) {
    self.seconds = Int64(cts.tv_sec)
    self.nanoseconds = Int32(cts.tv_nsec)
  }
}

Définition de la spécification du temps

Compte tenu de l'utilisation, appliquons le protocole Comparable. Après cela, j'ai pensé qu'il serait pratique d'appliquer ʻExpressibleByIntegerLiteral et ʻExpressibleByFloatLiteral ... De plus, lors de l'ajout ou de la soustraction, normalisons les «nanosecondes» pour qu'il s'agisse toujours d'un entier non négatif de sorte qu'une expression de temps soit déterminée de manière unique.

public struct TimeSpecification: Comparable,
                                 ExpressibleByIntegerLiteral,
                                 ExpressibleByFloatLiteral {
  public var seconds:Int64 = 0
  public var nanoseconds:Int32 = 0 {
    didSet { self.normalize() }
  }
  
  public init(seconds:Int64, nanoseconds:Int32) {
    self.seconds = seconds
    self.nanoseconds = nanoseconds
    self.normalize()
  }
  
  public mutating func normalize() {
    // `nanoseconds` must be always zero or positive value and less than 1_000_000_000
    if self.nanoseconds >= 1_000_000_000 {
      self.seconds += Int64(self.nanoseconds / 1_000_000_000)
      self.nanoseconds = self.nanoseconds % 1_000_000_000
    } else if self.nanoseconds < 0 {
      // For example,
      //   (seconds:3, nanoseconds:-2_123_456_789)
      //   -> (seconds:0, nanoseconds:876_543_211)
      self.seconds += Int64(self.nanoseconds / 1_000_000_000) - 1
      self.nanoseconds = self.nanoseconds % 1_000_000_000 + 1_000_000_000
    }
  }
}

Comment obtenir un horodatage?

Je me demandais quel type de spécification utiliser, mais ici j'ai défini ʻenum appelé Clocket j'ai essayé de l'obtenir en utilisant cette méthode. Par exemple, obtenez l'horloge système aveclet now = Clock.System.timeSpecification ()`. Dans la méthode, utilisez l'API du langage C telle quelle. Apparemment, il peut ne pas l'obtenir, alors j'ai décidé de le renvoyer comme facultatif. Si vous spécifiez l'horloge du calendrier sous OS X, il semble que vous ne pouvez obtenir l'heure qu'en microsecondes.

public enum Clock {
  case Calendar
  case System
  
  public func timeSpecification() -> TimeSpecification? {
    var c_timespec:CTimeSpec = CTimeSpec(tv_sec:0, tv_nsec:0)
    
    let clock_id:CInt
    var retval:CInt = -1
    
    #if os(Linux)
      clock_id = (self == .Calendar) ? CLOCK_REALTIME : CLOCK_MONOTONIC
      retval = clock_gettime(clock_id, &c_timespec)
    #elseif os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
      var clock_name: clock_serv_t = 0
      clock_id = (self == .Calendar) ? CALENDAR_CLOCK : SYSTEM_CLOCK
      retval = host_get_clock_service(mach_host_self(), clock_id, &clock_name)
      if retval != 0 { return nil }
      retval = clock_get_time(clock_name, &c_timespec)
      _ = mach_port_deallocate(mach_task_self(), clock_name)
    #endif
    
    return (retval == 0) ? TimeSpecification(c_timespec) : nil
  }
}

prime

Si quoi que ce soit, le script Ruby build-install.rb qui facilite la construction de la bibliothèque Ça a pris du temps. En fait, même s'il s'agit d'un projet Swift, le code Ruby représente 40%. Tehe.

Recommended Posts

Même avec Swift, horodatage en nanosecondes!
Divide devient 0 dans Swift
Tableau multidimensionnel dans Swift
Photothèque avec Swift UI