Skip to content

Commit

Permalink
Merge pull request #98 from Appliscale/moveGenerics
Browse files Browse the repository at this point in the history
Moving generics into helpers package
  • Loading branch information
afronski authored Mar 9, 2018
2 parents 904ce66 + 9b19e9f commit 395aa16
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 118 deletions.
78 changes: 78 additions & 0 deletions helpers/listhelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,81 @@ func SliceContains(list []string, a string) bool {
}
return false
}

func IsPlainMap(mp map[string]interface{}) bool {
// First we check is it more complex. If so - it is worth investigating and we should stop checking.
for _, m := range mp {
if _, ok := m.(map[string]interface{}); ok {
return false
} else if _, ok := m.([]interface{}); ok {
return false
}
}
// Ok, it isn't. So is there any <nil>?
if mapContainsNil(mp) { // Yes, it is - so it is a map worth investigating. This is not the map we're looking for.
return false
}

return true // There is no <nil> and no complexity - it is a plain, non-nil map.
}

func IsPlainSlice(slc []interface{}) bool {
// The same flow as in `isPlainMap` function.
for _, s := range slc {
if _, ok := s.(map[string]interface{}); ok {
return false
} else if _, ok := s.([]interface{}); ok {
return false
}
}

if sliceContainsNil(slc) {
return false
}

return true
}

func Discard(slice []interface{}, n interface{}) []interface{} {
result := []interface{}{}
for _, s := range slice {
if s != n {
result = append(result, s)
}
}
return result
}

// We check if the element is non-string, non-float64, non-boolean. Then it is another node or <nil>. There is no other option.
func IsNonStringFloatBool(v interface{}) bool {
var isString, isFloat, isBool bool
if _, ok := v.(string); ok {
isString = true
} else if _, ok := v.(float64); ok {
isFloat = true
} else if _, ok := v.(bool); ok {
isBool = true
}
if !isString && !isFloat && !isBool {
return true
}
return false
}

func mapContainsNil(mp map[string]interface{}) bool {
for _, m := range mp {
if m == nil {
return true
}
}
return false
}

func sliceContainsNil(slice []interface{}) bool {
for _, s := range slice {
if s == nil {
return true
}
}
return false
}
125 changes: 7 additions & 118 deletions offlinevalidator/offlinevalidator.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"strings"

"errors"

"github.com/Appliscale/perun/context"
"github.com/Appliscale/perun/helpers"
"github.com/Appliscale/perun/logger"
Expand Down Expand Up @@ -351,118 +352,6 @@ func getNilResources(resources map[string]template.Resource) []string {
return list
}

func sliceContains(slice []string, match string) bool {
for _, s := range slice {
if s == match {
return true
}
}
return false
}

func mapContainsNil(mp map[string]interface{}) bool {
for _, m := range mp {
if m == nil {
return true
}
}
return false
}

func sliceContainsNil(slice []interface{}) bool {
for _, s := range slice {
if s == nil {
return true
}
}
return false
}

// We check if the element is non-string, non-float64, non-boolean. Then it is another node or <nil>. There is no other option.
func isNonStringFloatBool(v interface{}) bool {
var isString, isFloat, isBool bool
if _, ok := v.(string); ok {
isString = true
} else if _, ok := v.(float64); ok {
isFloat = true
} else if _, ok := v.(bool); ok {
isBool = true
}
if !isString && !isFloat && !isBool {
return true
}
return false
}

func isPlainMap(mp map[string]interface{}) bool {
// First we check is it more complex. If so - it is worth investigating and we should stop checking.
for _, m := range mp {
if _, ok := m.(map[string]interface{}); ok {
return false
} else if _, ok := m.([]interface{}); ok {
return false
}
}
// Ok, it isn't. So is there any <nil>?
if mapContainsNil(mp) { // Yes, it is - so it is a map worth investigating. This is not the map we're looking for.
return false
}

return true // There is no <nil> and no complexity - it is a plain, non-nil map.
}

func isPlainSlice(slc []interface{}) bool {
// The same flow as in `isPlainMap` function.
for _, s := range slc {
if _, ok := s.(map[string]interface{}); ok {
return false
} else if _, ok := s.([]interface{}); ok {
return false
}
}

if sliceContainsNil(slc) {
return false
}

return true
}

func discard(slice []interface{}, n interface{}) []interface{} {
result := []interface{}{}
for _, s := range slice {
if s != n {
result = append(result, s)
}
}
return result
}

func lineAndCharacter(input string, offset int) (line int, character int) {
lf := rune(0x0A)

if offset > len(input) || offset < 0 {
return 0, 0
}

line = 1

for i, b := range input {
if b == lf {
if i < offset {
line++
character = 0
}
} else {
character++
}
if i == offset {
break
}
}
return line, character
}

func checkWhereIsNil(n interface{}, v interface{}, baseLevel string, logger *logger.Logger, fullPath []interface{}, dsc *interface{}) {
if v == nil { // Value we encountered is nil - this is the end of investigation.
where := ""
Expand All @@ -479,26 +368,26 @@ func checkWhereIsNil(n interface{}, v interface{}, baseLevel string, logger *log
}
logger.Warning(baseLevel + ": " + where + " <--- is nil.")
} else if mp, ok := v.(map[string]interface{}); ok { // Value we encountered is a map.
if isPlainMap(mp) { // Check is it plain, non-nil map.
if helpers.IsPlainMap(mp) { // Check is it plain, non-nil map.
// It is - we shouldn't dive into.
*dsc = n // The name is stored in the `discarded` container as the name of the blind alley.
} else {
for kmp, vmp := range mp {
if isNonStringFloatBool(vmp) {
if helpers.IsNonStringFloatBool(vmp) {
fullPath = append(fullPath, kmp)
fullPath = discard(fullPath, *dsc) // If the output path would be different, it seems that we've encountered some node which is not on the way to the <nil>. It will be discarded from the path. Otherwise the paths are the same and we hit the point.
fullPath = helpers.Discard(fullPath, *dsc) // If the output path would be different, it seems that we've encountered some node which is not on the way to the <nil>. It will be discarded from the path. Otherwise the paths are the same and we hit the point.
checkWhereIsNil(kmp, vmp, baseLevel, logger, fullPath, dsc)
}
}
}
} else if slc, ok := v.([]interface{}); ok { // The same flow as above.
if isPlainSlice(slc) {
if helpers.IsPlainSlice(slc) {
*dsc = n
} else {
for islc, vslc := range slc {
if isNonStringFloatBool(vslc) {
if helpers.IsNonStringFloatBool(vslc) {
fullPath = append(fullPath, islc)
fullPath = discard(fullPath, *dsc)
fullPath = helpers.Discard(fullPath, *dsc)
checkWhereIsNil(islc, vslc, baseLevel, logger, fullPath, dsc)
}
}
Expand Down

0 comments on commit 395aa16

Please sign in to comment.