Skip to content

Commit

Permalink
Switch C StdLib time implementation
Browse files Browse the repository at this point in the history
Not all platforms even _have_ the required functions.
  • Loading branch information
danhunsaker committed Jul 21, 2018
1 parent 4944abb commit 6c24a31
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 203 deletions.
19 changes: 19 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,22 @@ after_failure:

after_success:
- bash <(curl -s https://codecov.io/bash)
- |
if [[ -n ${TRAVIS_TAG} && ${TRAVIS_GO_VERSION} = '1.10.x' ]]
then
set -e
cd ${TRAVIS_BUILD_DIR}
./build-all
go get github.com/aktau/github-release
github-release info --user danhunsaker --repo calends --tag ${TRAVIS_TAG} ||
github-release release --user danhunsaker --repo calends --tag ${TRAVIS_TAG} --draft
for archive in $(find dist/ -iname '*.tgz')
do
github-release upload \
--user danhunsaker \
--repo calends \
--tag ${TRAVIS_TAG} \
--name "${archive#dist/}" \
--file "${archive}"
done
fi
28 changes: 28 additions & 0 deletions build-all
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

set -e

GOPATH=$(go env GOPATH)
TARGETS=${TARGETS:-linux/386,linux/amd64,linux/arm-5,linux/arm-6,linux/arm-7,linux/arm64,windows-4.0/*,windows-6.0/*,windows-6.1/*,windows-6.3/*,windows-10.0/*}

v=$(grep 'Version =' calends.go | awk '{ print $4 }')
VERSION=$(echo v${v//\"/})
unset v

go get github.com/karalabe/xgo
${GOPATH}/bin/xgo -buildmode=c-shared -dest=$(pwd)/dist/ -out=libcalends-${VERSION} -targets=${TARGETS} github.com/danhunsaker/calends/libcalends

for h in $(find dist/ -iname '*.h')
do
dir=${h/.h/}
mkdir -p ${dir}
mv ${dir}.h ${dir}/libcalends.h
# Linux
[ -e ${dir}.so ] && mv ${dir}.so ${dir}/libcalends.so
# Darwin
[ -e ${dir}.dylib ] && mv ${dir}.dylib ${dir}/libcalends.dylib
# Windows
[ -e ${dir}.dll ] && mv ${dir}.dll ${dir}/libcalends.dll
tar czf ${dir}.tgz -C ${dir} .
rm -rf ${dir}
done
8 changes: 4 additions & 4 deletions calendars/gregorian.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Supported Input Types:
Supported Format Strings:
- any format supported by the time library or
github.com/danhunsaker/go-datefmt (or github.com/olebedev/when for Offset)
github.com/knz/strtime (or github.com/olebedev/when for Offset)
*/
package calendars
Expand All @@ -21,7 +21,7 @@ import (
"strings"
"time"

datefmt "github.com/danhunsaker/go-datefmt"
"github.com/knz/strtime"
when "github.com/olebedev/when"
when_common "github.com/olebedev/when/rules/common"
when_en "github.com/olebedev/when/rules/en"
Expand Down Expand Up @@ -50,7 +50,7 @@ func init() {

if str != "" {
if strings.ContainsRune(format, '%') {
in, err = datefmt.Strptime(format, str)
in, err = strtime.Strptime(str, format)
} else {
in, err = time.Parse(format, str)
}
Expand All @@ -68,7 +68,7 @@ func init() {
func(stamp TAI64NAXURTime, format string) (date string, err error) {
tmp := time.Unix(stamp.Seconds, int64(stamp.Nano)).UTC()
if strings.ContainsRune(format, '%') {
date, err = datefmt.Strftime(format, tmp)
date, err = strtime.Strftime(tmp, format)
} else {
date = tmp.Format(format)
}
Expand Down
2 changes: 1 addition & 1 deletion calends.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type Calends struct {
}

// Version of the library
var Version = "0.0.3"
var Version = "0.0.4"

// Create is the mechanism for constructing new Calends objects.
/*
Expand Down
2 changes: 2 additions & 0 deletions dist/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
220 changes: 22 additions & 198 deletions libcalends/calends.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,43 @@ import (
"github.com/danhunsaker/calends"
)

var SHARDS = uint64(64)
var maxShards = uint64(64)

type ConcurrentMap []*ConcurrentMapShard
type concurrentMap []*concurrentMapShard

type ConcurrentMapShard struct {
type concurrentMapShard struct {
items map[uint64]interface{}
sync.RWMutex
}

func NewConcurrentMap() ConcurrentMap {
m := make(ConcurrentMap, SHARDS)
for i := uint64(0); i < SHARDS; i++ {
m[i] = &ConcurrentMapShard{items: make(map[uint64]interface{})}
func newConcurrentMap() concurrentMap {
m := make(concurrentMap, maxShards)
for i := uint64(0); i < maxShards; i++ {
m[i] = &concurrentMapShard{items: make(map[uint64]interface{})}
}
return m
}

func (m ConcurrentMap) getShard(key uint64) *ConcurrentMapShard {
return m[key%SHARDS]
func (m concurrentMap) getShard(key uint64) *concurrentMapShard {
return m[key%maxShards]
}

func (m ConcurrentMap) Store(key uint64, value interface{}) {
func (m concurrentMap) Store(key uint64, value interface{}) {
shard := m.getShard(key)
shard.Lock()
shard.items[key] = value
shard.Unlock()
}

func (m ConcurrentMap) Load(key uint64) (interface{}, bool) {
func (m concurrentMap) Load(key uint64) (interface{}, bool) {
shard := m.getShard(key)
shard.RLock()
val, ok := shard.items[key]
shard.RUnlock()
return val, ok
}

func (m ConcurrentMap) Length() (out uint64) {
func (m concurrentMap) Length() (out uint64) {
for _, shard := range m {
shard.RLock()
out += uint64(len(shard.items))
Expand All @@ -61,7 +61,7 @@ func (m ConcurrentMap) Length() (out uint64) {
return
}

func (m ConcurrentMap) All() (out []interface{}) {
func (m concurrentMap) All() (out []interface{}) {
for _, shard := range m {
shard.RLock()
for _, item := range shard.items {
Expand All @@ -72,30 +72,30 @@ func (m ConcurrentMap) All() (out []interface{}) {
return
}

func (m ConcurrentMap) Delete(key uint64) {
func (m concurrentMap) Delete(key uint64) {
shard := m.getShard(key)
shard.Lock()
delete(shard.items, key)
shard.Unlock()
}

type IdGenerator struct {
type idGenerator struct {
id uint64
}

func (generator *IdGenerator) Id() uint64 {
func (generator *idGenerator) Id() uint64 {
return atomic.AddUint64(&generator.id, 1)
}

var panicHandlers ConcurrentMap
var nextPanHandle IdGenerator
var instances ConcurrentMap
var nextInst IdGenerator
var panicHandlers concurrentMap
var nextPanHandle idGenerator
var instances concurrentMap
var nextInst idGenerator

func init() {
C.Calends_version = C.CString(calends.Version)
panicHandlers = NewConcurrentMap()
instances = NewConcurrentMap()
panicHandlers = newConcurrentMap()
instances = newConcurrentMap()
}

func instNum(c calends.Calends) C.ulonglong {
Expand All @@ -122,182 +122,6 @@ func calends_create(stamp interface{}, calendar, format *C.char) C.ulonglong {
return instNum(c)
}

//export Calends_release
func Calends_release(p C.ulonglong) {
instances.Delete(uint64(p))
}

//export Calends_create_string
func Calends_create_string(stamp, calendar, format *C.char) C.ulonglong {
return calends_create(C.GoString(stamp), calendar, format)
}

//export Calends_create_string_range
func Calends_create_string_range(start, end, calendar, format *C.char) C.ulonglong {
return calends_create(map[string]interface{}{
"start": C.GoString(start),
"end": C.GoString(end),
}, calendar, format)
}

//export Calends_create_string_start_period
func Calends_create_string_start_period(start, duration, calendar, format *C.char) C.ulonglong {
return calends_create(map[string]interface{}{
"start": C.GoString(start),
"duration": C.GoString(duration),
}, calendar, format)
}

//export Calends_create_string_end_period
func Calends_create_string_end_period(duration, end, calendar, format *C.char) C.ulonglong {
return calends_create(map[string]interface{}{
"duration": C.GoString(duration),
"end": C.GoString(end),
}, calendar, format)
}

//export Calends_create_long_long
func Calends_create_long_long(stamp C.longlong, calendar, format *C.char) C.ulonglong {
return calends_create(int(stamp), calendar, format)
}

//export Calends_create_long_long_range
func Calends_create_long_long_range(start, end C.longlong, calendar, format *C.char) C.ulonglong {
return calends_create(map[string]interface{}{
"start": int(start),
"end": int(end),
}, calendar, format)
}

//export Calends_create_long_long_start_period
func Calends_create_long_long_start_period(start, duration C.longlong, calendar, format *C.char) C.ulonglong {
return calends_create(map[string]interface{}{
"start": int(start),
"duration": int(duration),
}, calendar, format)
}

//export Calends_create_long_long_end_period
func Calends_create_long_long_end_period(duration, end C.longlong, calendar, format *C.char) C.ulonglong {
return calends_create(map[string]interface{}{
"duration": int(duration),
"end": int(end),
}, calendar, format)
}

//export Calends_create_double
func Calends_create_double(stamp C.double, calendar, format *C.char) C.ulonglong {
return calends_create(float64(stamp), calendar, format)
}

//export Calends_create_double_range
func Calends_create_double_range(start, end C.double, calendar, format *C.char) C.ulonglong {
return calends_create(map[string]interface{}{
"start": float64(start),
"end": float64(end),
}, calendar, format)
}

//export Calends_create_double_start_period
func Calends_create_double_start_period(start, duration C.double, calendar, format *C.char) C.ulonglong {
return calends_create(map[string]interface{}{
"start": float64(start),
"duration": float64(duration),
}, calendar, format)
}

//export Calends_create_double_end_period
func Calends_create_double_end_period(duration, end C.double, calendar, format *C.char) C.ulonglong {
return calends_create(map[string]interface{}{
"duration": float64(duration),
"end": float64(end),
}, calendar, format)
}

//export Calends_date
func Calends_date(p C.ulonglong, calendar, format *C.char) *C.char {
defer handlePanic()
c := instGet(p)
out, err := c.Date(C.GoString(calendar), C.GoString(format))
if err != nil {
panic(err)
}
return C.CString(out)
}

//export Calends_duration
func Calends_duration(p C.ulonglong) *C.char {
c := instGet(p)
return C.CString(c.Duration().String())
}

//export Calends_end_date
func Calends_end_date(p C.ulonglong, calendar, format *C.char) *C.char {
defer handlePanic()
c := instGet(p)
out, err := c.EndDate(C.GoString(calendar), C.GoString(format))
if err != nil {
panic(err)
}
return C.CString(out)
}

//export Calends_string
func Calends_string(p C.ulonglong) *C.char {
c := instGet(p)
return C.CString(c.String())
}

//export Calends_encode_text
func Calends_encode_text(p C.ulonglong) *C.char {
defer handlePanic()
c := instGet(p)
out, err := c.MarshalText()
if err != nil {
panic(err)
}
return C.CString(string(out))
}

//export Calends_decode_text
func Calends_decode_text(in *C.char) C.ulonglong {
defer handlePanic()
c := calends.Calends{}
err := c.UnmarshalText([]byte(C.GoString(in)))
if err != nil {
panic(err)
}
return instNum(c)
}

//export Calends_encode_json
func Calends_encode_json(p C.ulonglong) *C.char {
defer handlePanic()
c := instGet(p)
out, err := c.MarshalJSON()
if err != nil {
panic(err)
}
return C.CString(string(out))
}

//export Calends_decode_json
func Calends_decode_json(in *C.char) C.ulonglong {
defer handlePanic()
c := calends.Calends{}
err := c.UnmarshalJSON([]byte(C.GoString(in)))
if err != nil {
panic(err)
}
return instNum(c)
}

//export Calends_register_panic_handler
func Calends_register_panic_handler(handler C.Calends_panic_handler) {
id := nextPanHandle.Id()
panicHandlers.Store(id, handler)
}

func handlePanic() {
var err string

Expand Down
Loading

0 comments on commit 6c24a31

Please sign in to comment.