Skip to content

Commit b331abb

Browse files
committed
Decamel alloc optimization
1 parent a5e430b commit b331abb

20 files changed

+219
-121
lines changed

.github/workflows/test.yml

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,39 @@ jobs:
55
name: lint
66
runs-on: ubuntu-latest
77
steps:
8-
- uses: actions/checkout@v3
9-
- name: golangci-lint
10-
uses: golangci/golangci-lint-action@v2
11-
with:
12-
version: latest
13-
args: --timeout=5m
8+
- uses: actions/checkout@v3
9+
- name: golangci-lint
10+
uses: golangci/golangci-lint-action@v2
11+
with:
12+
version: latest
13+
args: --timeout=5m
1414
test:
15+
strategy:
16+
matrix:
17+
go-version: [1.18.x, 1.19.x, 1.20.x, 1.21.x]
18+
os: [windows-latest, ubuntu-latest, macos-latest]
19+
runs-on: ${{ matrix.os }}
20+
steps:
21+
- name: setup go
22+
uses: actions/setup-go@v2
23+
with:
24+
go-version: ${{ matrix.go-version }}
25+
- name: checkout
26+
uses: actions/checkout@v2
27+
- name: test
28+
run: make test
29+
test-cov:
1530
runs-on: ubuntu-latest
1631
steps:
17-
- name: setup
18-
uses: actions/setup-go@v2
19-
with:
20-
go-version: 1.19.x
21-
- name: checkout
22-
uses: actions/checkout@v2
23-
- name: test
24-
run: make test_cov_out
25-
- name: upload
26-
uses: codecov/codecov-action@v2
27-
with:
28-
files: ./coverage.txt
32+
- name: setup
33+
uses: actions/setup-go@v2
34+
with:
35+
go-version: 1.19.x
36+
- name: checkout
37+
uses: actions/checkout@v2
38+
- name: test
39+
run: make test_cov_out
40+
- name: upload
41+
uses: codecov/codecov-action@v2
42+
with:
43+
files: ./coverage.txt

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ coverage.*
1515

1616
# Output of the go coverage tool, specifically when used with LiteIDE
1717
*.out
18+
19+
dist/

.goreleaser.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# This is an example .goreleaser.yml file with some sensible defaults.
2+
# Make sure to check the documentation at https://goreleaser.com
3+
before:
4+
hooks:
5+
# You may remove this if you don't use go modules.
6+
- go mod tidy
7+
# you may remove this if you don't need go generate
8+
- go generate ./...
9+
builds:
10+
- skip: true
11+
12+
changelog:
13+
sort: asc
14+
filters:
15+
exclude:
16+
- '^docs:'
17+
- '^test:'
18+
19+
# The lines beneath this are called `modelines`. See `:help modeline`
20+
# Feel free to remove those if you don't want/use them.
21+
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
22+
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## Cangelog
1+
## Changelog
22

33
### Version history
44

Makefile

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,46 +58,43 @@ tinline_handler:
5858
$(GO) test -c -gcflags=-m=2 $(PKG_HANDLER) 2>&1 | ag 'inlin'
5959

6060
bench:
61-
$(GO) test -bench=. $(PKGS)
61+
$(GO) test $(TEST_ARGS) -bench=. $(PKGS)
6262

6363
bench_goid:
64-
$(GO) test -bench='BenchmarkGoid' $(PKG_ASSERT)
64+
$(GO) test $(TEST_ARGS) -bench='BenchmarkGoid' $(PKG_ASSERT)
6565

6666
bench_reca:
67-
$(GO) test -bench='BenchmarkRecursion.*' $(PKG_ERR2)
67+
$(GO) test $(TEST_ARGS) -bench='BenchmarkRecursion.*' $(PKG_ERR2)
6868

6969
bench_out:
70-
$(GO) test -bench='BenchmarkTryOut_.*' $(PKG_ERR2)
70+
$(GO) test $(TEST_ARGS) -bench='BenchmarkTryOut_.*' $(PKG_ERR2)
7171

7272
bench_go:
73-
$(GO) test -bench='BenchmarkTry_StringGenerics' $(PKG_ERR2)
74-
75-
bench_arec:
76-
$(GO) test -bench='BenchmarkRecursion.*' $(PKG_ERR2)
73+
$(GO) test $(TEST_ARGS) -bench='BenchmarkTry_StringGenerics' $(PKG_ERR2)
7774

7875
bench_that:
79-
$(GO) test -bench='BenchmarkThat.*' $(PKG_ASSERT)
76+
$(GO) test $(TEST_ARGS) -bench='BenchmarkThat.*' $(PKG_ASSERT)
8077

8178
bench_copy:
82-
$(GO) test -bench='Benchmark_CopyBuffer' $(PKG_TRY)
79+
$(GO) test $(TEST_ARGS) -bench='Benchmark_CopyBuffer' $(PKG_TRY)
8380

8481
bench_rece:
85-
$(GO) test -bench='BenchmarkRecursionWithTryAnd_Empty_Defer' $(PKG_ERR2)
82+
$(GO) test $(TEST_ARGS) -bench='BenchmarkRecursionWithTryAnd_Empty_Defer' $(PKG_ERR2)
8683

8784
bench_rec:
88-
$(GO) test -bench='BenchmarkRecursionWithOldErrorIfCheckAnd_Defer' $(PKG_ERR2)
85+
$(GO) test $(TEST_ARGS) -bench='BenchmarkRecursionWithOldErrorIfCheckAnd_Defer' $(PKG_ERR2)
8986

9087
bench_err2:
91-
$(GO) test -bench=. $(PKG_ERR2)
88+
$(GO) test $(TEST_ARGS) -bench=. $(PKG_ERR2)
9289

9390
bench_assert:
94-
$(GO) test -bench=. $(PKG_ASSERT)
91+
$(GO) test $(TEST_ARGS) -bench=. $(PKG_ASSERT)
9592

9693
bench_str:
97-
$(GO) test -bench=. $(PKG_STR)
94+
$(GO) test $(TEST_ARGS) -bench=. $(PKG_STR)
9895

9996
bench_x:
100-
$(GO) test -bench=. $(PKG_X)
97+
$(GO) test $(TEST_ARGS) -bench=. $(PKG_X)
10198

10299
vet: | test
103100
$(GO) vet $(PKGS)

README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ We also mark functions deprecated before they become obsolete. Usually, one
254254
released version before. We have tested this with a large code base in our
255255
systems, and it works wonderfully.
256256
257-
More information can be found in the scripts' [readme file](./scripts/README.md).
257+
More information can be found in the `scripts/` directory [readme
258+
file](./scripts/README.md).
258259
259260
## Assertion
260261
@@ -435,23 +436,29 @@ Please see the full version history from [CHANGELOG](./CHANGELOG.md).
435436
simplest `defer` function in the `err`-returning function** . (Please see
436437
the `defer` benchmarks in the `err2_test.go` and run `make bench_reca`)
437438
- the solution caused a change to API, where the core reason is Go's
438-
optimization "bug". (We don't have confirmation yet)
439+
optimization "bug". (We don't have confirmation yet.)
439440
- Changed API for deferred error handling: `defer err2.Handle/Catch()`
440-
- Deprecated:
441+
- *Obsolete*:
441442
```go
442-
defer err2.Handle(&err, func() { // <- relaying closure to access err val
443+
defer err2.Handle(&err, func() {}) // <- relaying closure to access err val
443444
```
444445
- Current version:
445446
```go
446-
defer err2.Handle(&err, func(error) error { // <- err val goes thru
447+
defer err2.Handle(&err, func(err error) error { return err }) // not a closure
447448
```
448-
- Added a new API:
449+
Because handler function is not relaying closures any more, it opens a new
450+
opportunity to use and build general helper functions: `err2.Noop`, etc.
451+
- Use auto-migration scripts especially for large code-bases. More information
452+
can be found in the `scripts/` directory's [readme file](./scripts/README.md).
453+
- Added a new (*experimental*) API:
449454
```go
450455
defer err2.Handle(&err, func(noerr bool) {
451456
assert.That(noerr) // noerr is always true!!
452457
doSomething()
453458
})
454459
```
460+
This is experimental because we aren't sure if this is something we want to
461+
have in the `err2` package.
455462
- Bug fixes: `ResultX.Logf()` now works as it should
456463
- More documentation
457464

err2.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ import (
77
"github.com/lainio/err2/internal/handler"
88
)
99

10+
type (
11+
// Handler is a function type used to process error values in Handle and
12+
// Catch. We currently have a few build-ins of the Handler: err2.Noop,
13+
// err2.Reset, etc.
14+
Handler func(error) error
15+
)
16+
1017
var (
1118
// ErrNotFound is similar *no-error* like io.EOF for those who really want to
1219
// use error return values to transport non errors. It's far better to have
@@ -101,28 +108,28 @@ func Handle(err *error, a ...any) {
101108
//
102109
// Catch support logging as well:
103110
//
104-
// defer err2.Catch("WARNING: catched errors: %s", name)
111+
// defer err2.Catch("WARNING: caught errors: %s", name)
105112
//
106113
// The preceding line catches the errors and panics and prints an annotated
107114
// error message about the error source (from where the error was thrown) to the
108115
// currently set log.
109116
//
110117
// The next one stops errors and panics, but allows you handle errors, like
111118
// cleanups, etc. The error handler function has same signature as Handle's
112-
// error handling function: func(err error) error. By returning nil resets the
119+
// error handling function, i.e., err2.Handler. By returning nil resets the
113120
// error, which allows e.g. prevent automatic error logs to happening.
114121
// Otherwise, the output results depends on the current Tracer and assert
115-
// settings. Default setting print call stacks for panics but not for errors.
122+
// settings. Default setting print call stacks for panics but not for errors:
116123
//
117124
// defer err2.Catch(func(err error) error { return err} )
118125
//
119126
// or if you you prefer to use dedicated helpers:
120127
//
121-
// defer err2.Catch(err2.Reset)
128+
// defer err2.Catch(err2.Noop)
122129
//
123130
// The last one calls your error handler, and you have an explicit panic
124131
// handler too, where you can e.g. continue panicking to propagate it for above
125-
// callers:
132+
// callers or stop it like below:
126133
//
127134
// defer err2.Catch(func(err error) error { return err }, func(p any) {})
128135
func Catch(a ...any) {
@@ -165,20 +172,26 @@ func Throwf(format string, args ...any) {
165172
panic(err)
166173
}
167174

168-
// Noop is predeclared helper to use with Handle and Catch. It keeps the current
175+
// Noop is a built-in helper to use with Handle and Catch. It keeps the current
169176
// error value the same. You can use it like this:
170177
//
171178
// defer err2.Handle(&err, err2.Noop)
172179
func Noop(err error) error { return err }
173180

174-
// Reset is predeclared helper to use with Handle and Catch. It sets the current
181+
// Reset is a built-in helper to use with Handle and Catch. It sets the current
175182
// error value to nil. You can use it like this to reset the error:
176183
//
177184
// defer err2.Handle(&err, err2.Reset)
178185
func Reset(error) error { return nil }
179186

180-
// Err is predeclared helper to use with Handle and Catch. It offers simplifier
181-
// for error handling function.
187+
// Err is a built-in helper to use with Handle and Catch. It offers simplifier
188+
// for error handling function for cases where you don't need to change the
189+
// current error value. For instance, if you want to just write error to stdout,
190+
// and don't want to use SetLogTracer and keep it to write to your logs.
191+
//
192+
// defer err2.Catch(err2.Err(func(err error) {
193+
// fmt.Println("ERROR:", err)
194+
// }))
182195
func Err(f func(err error)) func(error) error {
183196
return func(err error) error {
184197
f(err)

err2_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func TestHandle_NoError(t *testing.T) {
5353
var err error
5454
var handlerCalled bool
5555
defer func() {
56-
test.RequireEqual(t, handlerCalled, true)
56+
test.Require(t, handlerCalled)
5757
}()
5858
defer err2.Handle(&err, func(err error) error {
5959
// this should not be called, so lets try to fuckup things...

filecopy_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//go:build !windows
2+
13
package err2_test
24

35
import (

internal/handler/handler_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ func TestPreProcess_debug(t *testing.T) {
147147
// and that's what error stack tracing is all about
148148
Handle()
149149

150-
test.RequireEqual(t, panicHandlerCalled, false)
151-
test.RequireEqual(t, errorHandlerCalled, false)
152-
test.RequireEqual(t, nilHandlerCalled, false)
150+
test.Require(t, !panicHandlerCalled)
151+
test.Require(t, !errorHandlerCalled)
152+
test.Require(t, !nilHandlerCalled)
153153

154154
// See the name of this test function. Decamel it + error
155155
const want = "testing: t runner: error"

internal/str/str.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ func Decamel(s string) string {
3232
isUpper bool
3333
prevSkipped bool
3434
)
35+
b.Grow(2 * len(s))
36+
3537
for i, v := range s {
3638
skip := v == '(' || v == ')' || v == '*'
3739
if skip {

samples/README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,20 @@ Please play with the samples by editing them and running the main files:
44
- `main.go` just a starter for different playgrounds
55
- `main-play.go` general playground based on CopyFile and recursion
66
- `main-db-sample.go` simulates DB transaction and money transfer
7+
- `main-nil.go` samples and tests for logger and using `err2.Handle` for success
78

89
Run a default playground `play` mode:
910
```go
10-
go run main.go
11+
go run ./...
1112
```
1213

1314
Or run the DB based version to maybe better understand how powerful the
1415
automatic error string building is:
1516
```go
16-
go run main.go -mode db
17+
go run ./... -mode db
18+
```
19+
20+
You can print usage:
21+
```go
22+
go run ./... -h
1723
```

0 commit comments

Comments
 (0)