History variables: Difference between revisions

Go solution
(Added C# solution.)
(Go solution)
Line 94:
 
<pre>foobar <- foo <- 5
</pre>
=={{header|Go}}==
We're all in this for the extra points. Mallon and Takota seem happy with sequences, but time and timestamps were mentioned on LtU. Beyond a separate sequence for each history variable, timestamps enable multiple variables to be seen in a common temporal sequence. In Go, with it's attention to concurrency, this might be done with flexibility for proper handling of shared variables, and efficient handling of variables limited to a single thread.
<lang go>package main
 
import (
"fmt"
"sort"
"sync"
"time"
)
 
// data type for history variable (its an int)
type history struct {
timestamp tsFunc
hs []hset
}
 
// data type for timestamp generator
type tsFunc func() int64
 
// data type for a "set" event
type hset struct {
int // new value
t int64 // timestamp
}
 
// newHistory creates a history variable
func newHistory(ts tsFunc) history {
return history{ts, []hset{{t: ts()}}}
}
 
// int returns the current value
func (h history) int() int {
return h.hs[len(h.hs)-1].int
}
 
// set does what you expect and returns the timestamp recorded for the event
func (h *history) set(x int) int64 {
t := h.timestamp()
h.hs = append(h.hs, hset{x, t})
return t
}
 
// dump displays a complete history
func (h history) dump() {
for _, hs := range h.hs {
fmt.Println(time.NanosecondsToUTC(hs.t).Format(time.StampNano), hs.int)
}
}
 
// recall recalls the value stored in the history variable at time t.
// if the variable had not been created yet, ok is false.
func (h history) recall(t int64) (int, /*ok*/ bool) {
i := sort.Search(len(h.hs), func(i int) bool {
return h.hs[i].t > t
})
if i > 0 {
return h.hs[i-1].int, true
}
return 0, false
}
 
// newTimestamper returns a function that generates unique timestamps.
// Use a single timestamper for multiple history variables to preserve
// an unambiguous sequence of assignments across the multiple history
// variables within a single goroutine.
func newTimestamper() tsFunc {
var last int64
return func() int64 {
for { // busy wait for next clock tick
if t := time.Nanoseconds(); t > last {
last = t
break
}
}
return last
}
}
 
// newProtectedTimestamper generates unique timestamps for concurrent
// goroutines.
func newProtectedTimestamper() tsFunc {
var last int64
var m sync.Mutex
return func() int64 {
m.Lock()
for {
if t := time.Nanoseconds(); t > last {
last = t
break
}
}
m.Unlock()
return last
}
}
 
func main() {
// enable history variable support appropriate for single goroutine.
ts := newTimestamper()
// define a history variable
h := newHistory(ts)
// assign three values. (timestamps kept for future reference.)
var ref []int64
ref = append(ref, h.set(3))
ref = append(ref, h.set(1))
ref = append(ref, h.set(4))
fmt.Println("History of variable h:")
// non-destructively display history
h.dump()
// recall the three values. (this is non-destructive as well, but
// different than the dump in that values are recalled by time.)
fmt.Println("Recalling values:")
for _, t := range ref {
rv, _ := h.recall(t)
fmt.Println(rv)
}
}</lang>
Output:
<pre>
History of variable h:
Nov 30 03:39:38.795286000 0
Nov 30 03:39:38.795287000 3
Nov 30 03:39:38.795289000 1
Nov 30 03:39:38.795290000 4
Recalling values:
3
1
4
</pre>
 
1,707

edits