Skip to content

Commit 3d21e3a

Browse files
committed
Implemented generic algorithms (at lease until they are available in go stdlib...)
1 parent 856e791 commit 3d21e3a

File tree

10 files changed

+125
-54
lines changed

10 files changed

+125
-54
lines changed

internal/algorithms/slices.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to license@arduino.cc.
15+
16+
package f
17+
18+
// Filter takes a slice of type []T and a function of type func(T) bool. It returns
19+
// a newly allocated slice containing only those elements of the input slice that
20+
// satisfy the test function.
21+
func Filter[T any](values []T, test func(x T) bool) []T {
22+
res := []T{}
23+
for _, x := range values {
24+
if test(x) {
25+
res = append(res, x)
26+
}
27+
}
28+
return res
29+
}
30+
31+
// Map applies the mapping function to each element of the slice and returns a new
32+
// slice with the results in the same order.
33+
func Map[T any](values []T, mapping func(x T) T) []T {
34+
res := []T{}
35+
for _, x := range values {
36+
res = append(res, mapping(x))
37+
}
38+
return res
39+
}
40+
41+
// Equals return a functor that matches the given value
42+
func Equals[T comparable](value T) func(x T) bool {
43+
return func(x T) bool {
44+
return x == value
45+
}
46+
}
47+
48+
// NotEquals return a functor that does not match the given value
49+
func NotEquals[T comparable](value T) func(x T) bool {
50+
return func(x T) bool {
51+
return x != value
52+
}
53+
}

internal/algorithms/slices_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to license@arduino.cc.
15+
16+
package f_test
17+
18+
import (
19+
"strings"
20+
"testing"
21+
22+
f "github.com/arduino/arduino-cli/internal/algorithms"
23+
"github.com/stretchr/testify/require"
24+
)
25+
26+
func TestFilter(t *testing.T) {
27+
a := []string{"aaa", "bbb", "ccc"}
28+
require.Equal(t, []string{"bbb", "ccc"}, f.Filter(a, func(x string) bool { return x > "b" }))
29+
b := []int{5, 9, 15, 2, 4, -2}
30+
require.Equal(t, []int{5, 9, 15}, f.Filter(b, func(x int) bool { return x > 4 }))
31+
}
32+
33+
func TestIsEmpty(t *testing.T) {
34+
require.True(t, f.Equals(int(0))(0))
35+
require.False(t, f.Equals(int(1))(0))
36+
require.True(t, f.Equals("")(""))
37+
require.False(t, f.Equals("abc")(""))
38+
require.False(t, f.NotEquals(int(0))(0))
39+
require.True(t, f.NotEquals(int(1))(0))
40+
require.False(t, f.NotEquals("")(""))
41+
require.True(t, f.NotEquals("abc")(""))
42+
}
43+
44+
func TestMap(t *testing.T) {
45+
value := "hello, world , how are,you? "
46+
parts := f.Map(strings.Split(value, ","), strings.TrimSpace)
47+
48+
require.Equal(t, 4, len(parts))
49+
require.Equal(t, "hello", parts[0])
50+
require.Equal(t, "world", parts[1])
51+
require.Equal(t, "how are", parts[2])
52+
require.Equal(t, "you?", parts[3])
53+
}

legacy/builder/builder_utils/utils.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
"github.com/arduino/arduino-cli/arduino/globals"
2828
"github.com/arduino/arduino-cli/i18n"
29+
f "github.com/arduino/arduino-cli/internal/algorithms"
2930
"github.com/arduino/arduino-cli/legacy/builder/constants"
3031
"github.com/arduino/arduino-cli/legacy/builder/types"
3132
"github.com/arduino/arduino-cli/legacy/builder/utils"
@@ -262,10 +263,10 @@ func ObjFileIsUpToDate(sourceFile, objectFile, dependencyFile *paths.Path) (bool
262263
return false, errors.WithStack(err)
263264
}
264265

265-
rows = utils.Map(rows, removeEndingBackSlash)
266-
rows = utils.Map(rows, strings.TrimSpace)
267-
rows = utils.Map(rows, unescapeDep)
268-
rows = utils.Filter(rows, nonEmptyString)
266+
rows = f.Map(rows, removeEndingBackSlash)
267+
rows = f.Map(rows, strings.TrimSpace)
268+
rows = f.Map(rows, unescapeDep)
269+
rows = f.Filter(rows, f.NotEquals(""))
269270

270271
if len(rows) == 0 {
271272
return true, nil
@@ -327,10 +328,6 @@ func removeEndingBackSlash(s string) string {
327328
return strings.TrimSuffix(s, "\\")
328329
}
329330

330-
func nonEmptyString(s string) bool {
331-
return s != constants.EMPTY_STRING
332-
}
333-
334331
func CoreOrReferencedCoreHasChanged(corePath, targetCorePath, targetFile *paths.Path) bool {
335332

336333
targetFileStat, err := targetFile.Stat()

legacy/builder/gcc_preproc_runner.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"os/exec"
2020
"strings"
2121

22+
f "github.com/arduino/arduino-cli/internal/algorithms"
2223
"github.com/arduino/arduino-cli/legacy/builder/builder_utils"
2324
"github.com/arduino/arduino-cli/legacy/builder/types"
2425
"github.com/arduino/arduino-cli/legacy/builder/utils"
@@ -44,7 +45,7 @@ func prepareGCCPreprocRecipeProperties(ctx *types.Context, sourceFilePath *paths
4445
buildProperties.SetPath("source_file", sourceFilePath)
4546
buildProperties.SetPath("preprocessed_file_path", targetFilePath)
4647

47-
includesStrings := utils.Map(includes.AsStrings(), utils.WrapWithHyphenI)
48+
includesStrings := f.Map(includes.AsStrings(), utils.WrapWithHyphenI)
4849
buildProperties.Set("includes", strings.Join(includesStrings, " "))
4950

5051
if buildProperties.Get("recipe.preproc.macros") == "" {
@@ -65,7 +66,7 @@ func prepareGCCPreprocRecipeProperties(ctx *types.Context, sourceFilePath *paths
6566

6667
// Remove -MMD argument if present. Leaving it will make gcc try
6768
// to create a /dev/null.d dependency file, which won't work.
68-
cmd.Args = utils.Filter(cmd.Args, func(a string) bool { return a != "-MMD" })
69+
cmd.Args = f.Filter(cmd.Args, f.NotEquals("-MMD"))
6970

7071
return cmd, nil
7172
}

legacy/builder/phases/core_builder.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/arduino/arduino-cli/buildcache"
2424
"github.com/arduino/arduino-cli/i18n"
25+
f "github.com/arduino/arduino-cli/internal/algorithms"
2526
"github.com/arduino/arduino-cli/legacy/builder/builder_utils"
2627
"github.com/arduino/arduino-cli/legacy/builder/constants"
2728
"github.com/arduino/arduino-cli/legacy/builder/types"
@@ -77,7 +78,7 @@ func compileCore(ctx *types.Context, buildPath *paths.Path, buildCachePath *path
7778
if variantFolder != nil && variantFolder.IsDir() {
7879
includes = append(includes, variantFolder.String())
7980
}
80-
includes = utils.Map(includes, utils.WrapWithHyphenI)
81+
includes = f.Map(includes, utils.WrapWithHyphenI)
8182

8283
var err error
8384

legacy/builder/phases/libraries_builder.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"strings"
2020

2121
"github.com/arduino/arduino-cli/arduino/libraries"
22+
f "github.com/arduino/arduino-cli/internal/algorithms"
2223
"github.com/arduino/arduino-cli/legacy/builder/builder_utils"
2324
"github.com/arduino/arduino-cli/legacy/builder/constants"
2425
"github.com/arduino/arduino-cli/legacy/builder/types"
@@ -36,7 +37,7 @@ type LibrariesBuilder struct{}
3637
func (s *LibrariesBuilder) Run(ctx *types.Context) error {
3738
librariesBuildPath := ctx.LibrariesBuildPath
3839
buildProperties := ctx.BuildProperties
39-
includes := utils.Map(ctx.IncludeFolders.AsStrings(), utils.WrapWithHyphenI)
40+
includes := f.Map(ctx.IncludeFolders.AsStrings(), utils.WrapWithHyphenI)
4041
libs := ctx.ImportedLibraries
4142

4243
if err := librariesBuildPath.MkdirAll(); err != nil {

legacy/builder/phases/linker.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package phases
1818
import (
1919
"strings"
2020

21+
f "github.com/arduino/arduino-cli/internal/algorithms"
2122
"github.com/arduino/arduino-cli/legacy/builder/builder_utils"
2223
"github.com/arduino/arduino-cli/legacy/builder/constants"
2324
"github.com/arduino/arduino-cli/legacy/builder/types"
@@ -64,7 +65,7 @@ func (s *Linker) Run(ctx *types.Context) error {
6465
}
6566

6667
func link(ctx *types.Context, objectFiles paths.PathList, coreDotARelPath *paths.Path, coreArchiveFilePath *paths.Path, buildProperties *properties.Map) error {
67-
objectFileList := strings.Join(utils.Map(objectFiles.AsStrings(), wrapWithDoubleQuotes), " ")
68+
objectFileList := strings.Join(f.Map(objectFiles.AsStrings(), wrapWithDoubleQuotes), " ")
6869

6970
// If command line length is too big (> 30000 chars), try to collect the object files into archives
7071
// and use that archives to complete the build.
@@ -102,7 +103,7 @@ func link(ctx *types.Context, objectFiles paths.PathList, coreDotARelPath *paths
102103
}
103104
}
104105

105-
objectFileList = strings.Join(utils.Map(archives.AsStrings(), wrapWithDoubleQuotes), " ")
106+
objectFileList = strings.Join(f.Map(archives.AsStrings(), wrapWithDoubleQuotes), " ")
106107
objectFileList = "-Wl,--whole-archive " + objectFileList + " -Wl,--no-whole-archive"
107108
}
108109

legacy/builder/phases/sketch_builder.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package phases
1717

1818
import (
19+
f "github.com/arduino/arduino-cli/internal/algorithms"
1920
"github.com/arduino/arduino-cli/legacy/builder/builder_utils"
2021
"github.com/arduino/arduino-cli/legacy/builder/types"
2122
"github.com/arduino/arduino-cli/legacy/builder/utils"
@@ -27,7 +28,7 @@ type SketchBuilder struct{}
2728
func (s *SketchBuilder) Run(ctx *types.Context) error {
2829
sketchBuildPath := ctx.SketchBuildPath
2930
buildProperties := ctx.BuildProperties
30-
includes := utils.Map(ctx.IncludeFolders.AsStrings(), utils.WrapWithHyphenI)
31+
includes := f.Map(ctx.IncludeFolders.AsStrings(), utils.WrapWithHyphenI)
3132

3233
if err := sketchBuildPath.MkdirAll(); err != nil {
3334
return errors.WithStack(err)

legacy/builder/test/utils_test.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package test
1717

1818
import (
19-
"strings"
2019
"testing"
2120

2221
"github.com/arduino/arduino-cli/legacy/builder/utils"
@@ -42,17 +41,6 @@ func TestPrintableCommand(t *testing.T) {
4241
require.Equal(t, correct, result)
4342
}
4443

45-
func TestMapTrimSpace(t *testing.T) {
46-
value := "hello, world , how are,you? "
47-
parts := utils.Map(strings.Split(value, ","), utils.TrimSpace)
48-
49-
require.Equal(t, 4, len(parts))
50-
require.Equal(t, "hello", parts[0])
51-
require.Equal(t, "world", parts[1])
52-
require.Equal(t, "how are", parts[2])
53-
require.Equal(t, "you?", parts[3])
54-
}
55-
5644
func TestQuoteCppString(t *testing.T) {
5745
cases := map[string]string{
5846
`foo`: `"foo"`,

legacy/builder/utils/utils.go

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"unicode"
2929

3030
"github.com/arduino/arduino-cli/i18n"
31+
f "github.com/arduino/arduino-cli/internal/algorithms"
3132
"github.com/arduino/arduino-cli/legacy/builder/gohasissues"
3233
"github.com/arduino/arduino-cli/legacy/builder/types"
3334
paths "github.com/arduino/go-paths-helper"
@@ -119,36 +120,10 @@ func IsSCCSFile(file os.FileInfo) bool {
119120
return SOURCE_CONTROL_FOLDERS[name]
120121
}
121122

122-
type mapFunc func(string) string
123-
124-
func Map(slice []string, fn mapFunc) []string {
125-
newSlice := []string{}
126-
for _, elem := range slice {
127-
newSlice = append(newSlice, fn(elem))
128-
}
129-
return newSlice
130-
}
131-
132-
type filterFunc func(string) bool
133-
134-
func Filter(slice []string, fn filterFunc) []string {
135-
newSlice := []string{}
136-
for _, elem := range slice {
137-
if fn(elem) {
138-
newSlice = append(newSlice, elem)
139-
}
140-
}
141-
return newSlice
142-
}
143-
144123
func WrapWithHyphenI(value string) string {
145124
return "\"-I" + value + "\""
146125
}
147126

148-
func TrimSpace(value string) string {
149-
return strings.TrimSpace(value)
150-
}
151-
152127
func printableArgument(arg string) string {
153128
if strings.ContainsAny(arg, "\"\\ \t") {
154129
arg = strings.Replace(arg, "\\", "\\\\", -1)
@@ -164,7 +139,7 @@ func printableArgument(arg string) string {
164139
// probably not for shell interpretation. This essentially reverses
165140
// ParseCommandLine.
166141
func PrintableCommand(parts []string) string {
167-
return strings.Join(Map(parts, printableArgument), " ")
142+
return strings.Join(f.Map(parts, printableArgument), " ")
168143
}
169144

170145
const (

0 commit comments

Comments
 (0)