From ee1414c010e5a2b8c99214eaea5522eb99b91c79 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 30 Sep 2019 14:23:15 +0800 Subject: [PATCH] add UnmarshalJSON func tion for gmap/gvar --- container/garray/garray_sorted_any.go | 9 ++- container/glist/glist.go | 16 +++++ container/glist/glist_z_unit_test.go | 35 +++++++++++ container/gmap/gmap_hash_any_any_map.go | 18 ++++++ container/gmap/gmap_hash_int_any_map.go | 14 +++++ container/gmap/gmap_hash_int_int_map.go | 14 +++++ container/gmap/gmap_hash_int_str_map.go | 14 +++++ container/gmap/gmap_hash_str_any_map.go | 14 +++++ container/gmap/gmap_hash_str_int_map.go | 14 +++++ container/gmap/gmap_hash_str_str_map.go | 14 +++++ container/gmap/gmap_link_map.go | 23 +++++++ ...ny_test.go => gmap_z_unit_any_any_test.go} | 47 ++++++++++++++ ...ny_test.go => gmap_z_unit_int_any_test.go} | 32 ++++++++++ ...nt_test.go => gmap_z_unit_int_int_test.go} | 32 ++++++++++ ...tr_test.go => gmap_z_unit_int_str_test.go} | 32 ++++++++++ ...p_test.go => gmap_z_unit_list_map_test.go} | 61 ++++++++++++++++--- ...ny_test.go => gmap_z_unit_str_any_test.go} | 46 ++++++++++++++ ...nt_test.go => gmap_z_unit_str_int_test.go} | 46 ++++++++++++++ ...tr_test.go => gmap_z_unit_str_str_test.go} | 46 ++++++++++++++ ...p_test.go => gmap_z_unit_tree_map_test.go} | 57 +++++++++++++++-- container/gtree/gtree_redblacktree.go | 42 ++++++++++++- container/gvar/gvar.go | 32 +++++----- container/gvar/gvar_z_unit_test.go | 54 ++++++++++++++-- 23 files changed, 676 insertions(+), 36 deletions(-) rename container/gmap/{gmap_z_any_any_test.go => gmap_z_unit_any_any_test.go} (80%) rename container/gmap/{gmap_z_int_any_test.go => gmap_z_unit_int_any_test.go} (86%) rename container/gmap/{gmap_z_int_int_test.go => gmap_z_unit_int_int_test.go} (86%) rename container/gmap/{gmap_z_int_str_test.go => gmap_z_unit_int_str_test.go} (87%) rename container/gmap/{gmap_z_link_map_test.go => gmap_z_unit_list_map_test.go} (72%) rename container/gmap/{gmap_z_str_any_test.go => gmap_z_unit_str_any_test.go} (81%) rename container/gmap/{gmap_z_str_int_test.go => gmap_z_unit_str_int_test.go} (81%) rename container/gmap/{gmap_z_str_str_test.go => gmap_z_unit_str_str_test.go} (81%) rename container/gmap/{gmap_z_tree_map_test.go => gmap_z_unit_tree_map_test.go} (69%) diff --git a/container/garray/garray_sorted_any.go b/container/garray/garray_sorted_any.go index 5fc545a92..2fca9475c 100644 --- a/container/garray/garray_sorted_any.go +++ b/container/garray/garray_sorted_any.go @@ -9,6 +9,7 @@ package garray import ( "bytes" "encoding/json" + "github.com/gogf/gf/util/gutil" "math" "sort" @@ -85,6 +86,10 @@ func (a *SortedArray) SetComparator(comparator func(a, b interface{}) int) { a.mu.Lock() defer a.mu.Unlock() a.comparator = comparator + // Resort the array if comparator is changed. + sort.Slice(a.array, func(i, j int) bool { + return a.comparator(a.array[i], a.array[j]) < 0 + }) } // Sort sorts the array in increasing order. @@ -564,8 +569,8 @@ func (a *SortedArray) UnmarshalJSON(b []byte) error { a.mu = rwmutex.New() a.array = make([]interface{}, 0) a.unique = gtype.NewBool() - // Note that the comparator is nil in default. - a.comparator = nil + // Note that the comparator is string comparator in default. + a.comparator = gutil.ComparatorString } a.mu.Lock() defer a.mu.Unlock() diff --git a/container/glist/glist.go b/container/glist/glist.go index a953c734d..9e24d85c1 100644 --- a/container/glist/glist.go +++ b/container/glist/glist.go @@ -377,3 +377,19 @@ func (l *List) IteratorDesc(f func(e *Element) bool) { func (l *List) MarshalJSON() ([]byte, error) { return json.Marshal(l.FrontAll()) } + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (l *List) UnmarshalJSON(b []byte) error { + if l.mu == nil { + l.mu = rwmutex.New() + l.list = list.New() + } + l.mu.Lock() + defer l.mu.Unlock() + var array []interface{} + if err := json.Unmarshal(b, &array); err != nil { + return err + } + l.PushBacks(array) + return nil +} diff --git a/container/glist/glist_z_unit_test.go b/container/glist/glist_z_unit_test.go index 0e2a33ef2..5ffbabb45 100644 --- a/container/glist/glist_z_unit_test.go +++ b/container/glist/glist_z_unit_test.go @@ -8,6 +8,7 @@ package glist import ( "container/list" + "encoding/json" "github.com/gogf/gf/test/gtest" "github.com/gogf/gf/util/gconv" @@ -583,3 +584,37 @@ func TestList_Iterator(t *testing.T) { l.Iterator(fun1) checkList(t, l, []interface{}{"e", "d", "c", "b", "a"}) } + +func TestList_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + a := []interface{}{"a", "b", "c"} + l := New() + l.PushBacks(a) + b1, err1 := json.Marshal(l) + b2, err2 := json.Marshal(a) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + a := []interface{}{"a", "b", "c"} + l := New() + b, err := json.Marshal(a) + gtest.Assert(err, nil) + + err = json.Unmarshal(b, l) + gtest.Assert(err, nil) + gtest.Assert(l.FrontAll(), a) + }) + gtest.Case(t, func() { + var l List + a := []interface{}{"a", "b", "c"} + b, err := json.Marshal(a) + gtest.Assert(err, nil) + + err = json.Unmarshal(b, &l) + gtest.Assert(err, nil) + gtest.Assert(l.FrontAll(), a) + }) +} diff --git a/container/gmap/gmap_hash_any_any_map.go b/container/gmap/gmap_hash_any_any_map.go index b49c2eecc..028824304 100644 --- a/container/gmap/gmap_hash_any_any_map.go +++ b/container/gmap/gmap_hash_any_any_map.go @@ -377,3 +377,21 @@ func (m *AnyAnyMap) Merge(other *AnyAnyMap) { func (m *AnyAnyMap) MarshalJSON() ([]byte, error) { return json.Marshal(gconv.Map(m.Map())) } + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (m *AnyAnyMap) UnmarshalJSON(b []byte) error { + if m.mu == nil { + m.mu = rwmutex.New() + m.data = make(map[interface{}]interface{}) + } + m.mu.Lock() + defer m.mu.Unlock() + var data map[string]interface{} + if err := json.Unmarshal(b, &data); err != nil { + return err + } + for k, v := range data { + m.data[k] = v + } + return nil +} diff --git a/container/gmap/gmap_hash_int_any_map.go b/container/gmap/gmap_hash_int_any_map.go index 64ead24a1..465610627 100644 --- a/container/gmap/gmap_hash_int_any_map.go +++ b/container/gmap/gmap_hash_int_any_map.go @@ -368,3 +368,17 @@ func (m *IntAnyMap) MarshalJSON() ([]byte, error) { defer m.mu.RUnlock() return json.Marshal(m.data) } + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (m *IntAnyMap) UnmarshalJSON(b []byte) error { + if m.mu == nil { + m.mu = rwmutex.New() + m.data = make(map[int]interface{}) + } + m.mu.Lock() + defer m.mu.Unlock() + if err := json.Unmarshal(b, &m.data); err != nil { + return err + } + return nil +} diff --git a/container/gmap/gmap_hash_int_int_map.go b/container/gmap/gmap_hash_int_int_map.go index b4c67406d..de178ec39 100644 --- a/container/gmap/gmap_hash_int_int_map.go +++ b/container/gmap/gmap_hash_int_int_map.go @@ -344,3 +344,17 @@ func (m *IntIntMap) MarshalJSON() ([]byte, error) { defer m.mu.RUnlock() return json.Marshal(m.data) } + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (m *IntIntMap) UnmarshalJSON(b []byte) error { + if m.mu == nil { + m.mu = rwmutex.New() + m.data = make(map[int]int) + } + m.mu.Lock() + defer m.mu.Unlock() + if err := json.Unmarshal(b, &m.data); err != nil { + return err + } + return nil +} diff --git a/container/gmap/gmap_hash_int_str_map.go b/container/gmap/gmap_hash_int_str_map.go index e3055982b..4da07d542 100644 --- a/container/gmap/gmap_hash_int_str_map.go +++ b/container/gmap/gmap_hash_int_str_map.go @@ -345,3 +345,17 @@ func (m *IntStrMap) MarshalJSON() ([]byte, error) { defer m.mu.RUnlock() return json.Marshal(m.data) } + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (m *IntStrMap) UnmarshalJSON(b []byte) error { + if m.mu == nil { + m.mu = rwmutex.New() + m.data = make(map[int]string) + } + m.mu.Lock() + defer m.mu.Unlock() + if err := json.Unmarshal(b, &m.data); err != nil { + return err + } + return nil +} diff --git a/container/gmap/gmap_hash_str_any_map.go b/container/gmap/gmap_hash_str_any_map.go index 017be0fdc..6a42ae2fc 100644 --- a/container/gmap/gmap_hash_str_any_map.go +++ b/container/gmap/gmap_hash_str_any_map.go @@ -370,3 +370,17 @@ func (m *StrAnyMap) MarshalJSON() ([]byte, error) { defer m.mu.RUnlock() return json.Marshal(m.data) } + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (m *StrAnyMap) UnmarshalJSON(b []byte) error { + if m.mu == nil { + m.mu = rwmutex.New() + m.data = make(map[string]interface{}) + } + m.mu.Lock() + defer m.mu.Unlock() + if err := json.Unmarshal(b, &m.data); err != nil { + return err + } + return nil +} diff --git a/container/gmap/gmap_hash_str_int_map.go b/container/gmap/gmap_hash_str_int_map.go index c270f7975..0f6ce98d7 100644 --- a/container/gmap/gmap_hash_str_int_map.go +++ b/container/gmap/gmap_hash_str_int_map.go @@ -347,3 +347,17 @@ func (m *StrIntMap) MarshalJSON() ([]byte, error) { defer m.mu.RUnlock() return json.Marshal(m.data) } + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (m *StrIntMap) UnmarshalJSON(b []byte) error { + if m.mu == nil { + m.mu = rwmutex.New() + m.data = make(map[string]int) + } + m.mu.Lock() + defer m.mu.Unlock() + if err := json.Unmarshal(b, &m.data); err != nil { + return err + } + return nil +} diff --git a/container/gmap/gmap_hash_str_str_map.go b/container/gmap/gmap_hash_str_str_map.go index d674d1c11..e2d8f800b 100644 --- a/container/gmap/gmap_hash_str_str_map.go +++ b/container/gmap/gmap_hash_str_str_map.go @@ -347,3 +347,17 @@ func (m *StrStrMap) MarshalJSON() ([]byte, error) { defer m.mu.RUnlock() return json.Marshal(m.data) } + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (m *StrStrMap) UnmarshalJSON(b []byte) error { + if m.mu == nil { + m.mu = rwmutex.New() + m.data = make(map[string]string) + } + m.mu.Lock() + defer m.mu.Unlock() + if err := json.Unmarshal(b, &m.data); err != nil { + return err + } + return nil +} diff --git a/container/gmap/gmap_link_map.go b/container/gmap/gmap_link_map.go index 788e038bd..b3807792e 100644 --- a/container/gmap/gmap_link_map.go +++ b/container/gmap/gmap_link_map.go @@ -412,3 +412,26 @@ func (m *ListMap) Merge(other *ListMap) { func (m *ListMap) MarshalJSON() ([]byte, error) { return json.Marshal(gconv.Map(m.Map())) } + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (m *ListMap) UnmarshalJSON(b []byte) error { + if m.mu == nil { + m.mu = rwmutex.New() + m.data = make(map[interface{}]*glist.Element) + m.list = glist.New() + } + m.mu.Lock() + defer m.mu.Unlock() + var data map[string]interface{} + if err := json.Unmarshal(b, &data); err != nil { + return err + } + for key, value := range data { + if e, ok := m.data[key]; !ok { + m.data[key] = m.list.PushBack(&gListMapNode{key, value}) + } else { + e.Value = &gListMapNode{key, value} + } + } + return nil +} diff --git a/container/gmap/gmap_z_any_any_test.go b/container/gmap/gmap_z_unit_any_any_test.go similarity index 80% rename from container/gmap/gmap_z_any_any_test.go rename to container/gmap/gmap_z_unit_any_any_test.go index 355fbae6e..42305c4f5 100644 --- a/container/gmap/gmap_z_any_any_test.go +++ b/container/gmap/gmap_z_unit_any_any_test.go @@ -7,6 +7,9 @@ package gmap_test import ( + "encoding/json" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/util/gconv" "testing" "github.com/gogf/gf/container/gmap" @@ -174,3 +177,47 @@ func Test_AnyAnyMap_FilterEmpty(t *testing.T) { gtest.Assert(m.Get(1), nil) gtest.Assert(m.Get(2), 2) } + +func Test_AnyAnyMap_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + data := g.MapAnyAny{ + "k1": "v1", + "k2": "v2", + } + m1 := gmap.NewAnyAnyMapFrom(data) + b1, err1 := json.Marshal(m1) + b2, err2 := json.Marshal(gconv.Map(data)) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + data := g.MapAnyAny{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(gconv.Map(data)) + gtest.Assert(err, nil) + + m := gmap.New() + err = json.Unmarshal(b, m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) + gtest.Case(t, func() { + data := g.MapAnyAny{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(gconv.Map(data)) + gtest.Assert(err, nil) + + var m gmap.Map + err = json.Unmarshal(b, &m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) +} diff --git a/container/gmap/gmap_z_int_any_test.go b/container/gmap/gmap_z_unit_int_any_test.go similarity index 86% rename from container/gmap/gmap_z_int_any_test.go rename to container/gmap/gmap_z_unit_int_any_test.go index 4a35e103e..a9c2df3e6 100644 --- a/container/gmap/gmap_z_int_any_test.go +++ b/container/gmap/gmap_z_unit_int_any_test.go @@ -7,6 +7,8 @@ package gmap_test import ( + "encoding/json" + "github.com/gogf/gf/frame/g" "testing" "github.com/gogf/gf/container/gmap" @@ -171,3 +173,33 @@ func Test_IntAnyMap_FilterEmpty(t *testing.T) { gtest.Assert(m.Size(), 1) gtest.Assert(m.Get(2), 2) } + +func Test_IntAnyMap_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + data := g.MapIntAny{ + 1: "v1", + 2: "v2", + } + m1 := gmap.NewIntAnyMapFrom(data) + b1, err1 := json.Marshal(m1) + b2, err2 := json.Marshal(data) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + data := g.MapIntAny{ + 1: "v1", + 2: "v2", + } + b, err := json.Marshal(data) + gtest.Assert(err, nil) + + m := gmap.NewIntAnyMap() + err = json.Unmarshal(b, m) + gtest.Assert(err, nil) + gtest.Assert(m.Get(1), data[1]) + gtest.Assert(m.Get(2), data[2]) + }) +} diff --git a/container/gmap/gmap_z_int_int_test.go b/container/gmap/gmap_z_unit_int_int_test.go similarity index 86% rename from container/gmap/gmap_z_int_int_test.go rename to container/gmap/gmap_z_unit_int_int_test.go index b7bd4b7b6..4e376ecff 100644 --- a/container/gmap/gmap_z_int_int_test.go +++ b/container/gmap/gmap_z_unit_int_int_test.go @@ -7,6 +7,8 @@ package gmap_test import ( + "encoding/json" + "github.com/gogf/gf/frame/g" "testing" "github.com/gogf/gf/container/gmap" @@ -174,3 +176,33 @@ func Test_IntIntMap_FilterEmpty(t *testing.T) { gtest.Assert(m.Size(), 1) gtest.Assert(m.Get(2), 2) } + +func Test_IntIntMap_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + data := g.MapIntInt{ + 1: 10, + 2: 20, + } + m1 := gmap.NewIntIntMapFrom(data) + b1, err1 := json.Marshal(m1) + b2, err2 := json.Marshal(data) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + data := g.MapIntInt{ + 1: 10, + 2: 20, + } + b, err := json.Marshal(data) + gtest.Assert(err, nil) + + m := gmap.NewIntIntMap() + err = json.Unmarshal(b, m) + gtest.Assert(err, nil) + gtest.Assert(m.Get(1), data[1]) + gtest.Assert(m.Get(2), data[2]) + }) +} diff --git a/container/gmap/gmap_z_int_str_test.go b/container/gmap/gmap_z_unit_int_str_test.go similarity index 87% rename from container/gmap/gmap_z_int_str_test.go rename to container/gmap/gmap_z_unit_int_str_test.go index 3c95b51dd..b348ccbfe 100644 --- a/container/gmap/gmap_z_int_str_test.go +++ b/container/gmap/gmap_z_unit_int_str_test.go @@ -7,6 +7,8 @@ package gmap_test import ( + "encoding/json" + "github.com/gogf/gf/frame/g" "testing" "github.com/gogf/gf/container/gmap" @@ -175,3 +177,33 @@ func Test_IntStrMap_FilterEmpty(t *testing.T) { gtest.Assert(m.Size(), 1) gtest.Assert(m.Get(2), "2") } + +func Test_IntStrMap_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + data := g.MapIntStr{ + 1: "v1", + 2: "v2", + } + m1 := gmap.NewIntStrMapFrom(data) + b1, err1 := json.Marshal(m1) + b2, err2 := json.Marshal(data) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + data := g.MapIntStr{ + 1: "v1", + 2: "v2", + } + b, err := json.Marshal(data) + gtest.Assert(err, nil) + + m := gmap.NewIntStrMap() + err = json.Unmarshal(b, m) + gtest.Assert(err, nil) + gtest.Assert(m.Get(1), data[1]) + gtest.Assert(m.Get(2), data[2]) + }) +} diff --git a/container/gmap/gmap_z_link_map_test.go b/container/gmap/gmap_z_unit_list_map_test.go similarity index 72% rename from container/gmap/gmap_z_link_map_test.go rename to container/gmap/gmap_z_unit_list_map_test.go index 5f5c606ff..a8f75838c 100644 --- a/container/gmap/gmap_z_link_map_test.go +++ b/container/gmap/gmap_z_unit_list_map_test.go @@ -7,6 +7,8 @@ package gmap_test import ( + "encoding/json" + "github.com/gogf/gf/util/gconv" "testing" "github.com/gogf/gf/container/gmap" @@ -14,7 +16,7 @@ import ( "github.com/gogf/gf/test/gtest" ) -func Test_List_Map_Basic(t *testing.T) { +func Test_ListMap_Basic(t *testing.T) { gtest.Case(t, func() { m := gmap.NewListMap() m.Set("key1", "val1") @@ -48,7 +50,7 @@ func Test_List_Map_Basic(t *testing.T) { gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"}) }) } -func Test_List_Map_Set_Fun(t *testing.T) { +func Test_ListMap_Set_Fun(t *testing.T) { m := gmap.NewListMap() m.GetOrSetFunc("fun", getValue) m.GetOrSetFuncLock("funlock", getValue) @@ -59,14 +61,14 @@ func Test_List_Map_Set_Fun(t *testing.T) { gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false) } -func Test_List_Map_Batch(t *testing.T) { +func Test_ListMap_Batch(t *testing.T) { m := gmap.NewListMap() m.Sets(map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"}) gtest.Assert(m.Map(), map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"}) m.Removes([]interface{}{"key1", 1}) gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"}) } -func Test_List_Map_Iterator(t *testing.T) { +func Test_ListMap_Iterator(t *testing.T) { expect := map[interface{}]interface{}{1: 1, "key1": "val1"} m := gmap.NewListMapFrom(expect) @@ -89,7 +91,7 @@ func Test_List_Map_Iterator(t *testing.T) { gtest.Assert(j, 1) } -func Test_List_Map_Clone(t *testing.T) { +func Test_ListMap_Clone(t *testing.T) { //clone 方法是深克隆 m := gmap.NewListMapFrom(map[interface{}]interface{}{1: 1, "key1": "val1"}) m_clone := m.Clone() @@ -102,7 +104,7 @@ func Test_List_Map_Clone(t *testing.T) { gtest.AssertIN("key1", m.Keys()) } -func Test_List_Map_Basic_Merge(t *testing.T) { +func Test_ListMap_Basic_Merge(t *testing.T) { m1 := gmap.NewListMap() m2 := gmap.NewListMap() m1.Set("key1", "val1") @@ -111,7 +113,7 @@ func Test_List_Map_Basic_Merge(t *testing.T) { gtest.Assert(m1.Map(), map[interface{}]interface{}{"key1": "val1", "key2": "val2"}) } -func Test_List_Map_Order(t *testing.T) { +func Test_ListMap_Order(t *testing.T) { m := gmap.NewListMap() m.Set("k1", "v1") m.Set("k2", "v2") @@ -130,3 +132,48 @@ func Test_ListMap_FilterEmpty(t *testing.T) { gtest.Assert(m.Size(), 1) gtest.Assert(m.Get(2), "2") } + +func Test_ListMap_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + data := g.MapAnyAny{ + "k1": "v1", + "k2": "v2", + } + m1 := gmap.NewListMapFrom(data) + b1, err1 := json.Marshal(m1) + b2, err2 := json.Marshal(gconv.Map(data)) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + data := g.MapAnyAny{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(gconv.Map(data)) + gtest.Assert(err, nil) + + m := gmap.NewListMap() + err = json.Unmarshal(b, m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) + + gtest.Case(t, func() { + data := g.MapAnyAny{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(gconv.Map(data)) + gtest.Assert(err, nil) + + var m gmap.ListMap + err = json.Unmarshal(b, &m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) +} diff --git a/container/gmap/gmap_z_str_any_test.go b/container/gmap/gmap_z_unit_str_any_test.go similarity index 81% rename from container/gmap/gmap_z_str_any_test.go rename to container/gmap/gmap_z_unit_str_any_test.go index 4441f0dc1..831e07108 100644 --- a/container/gmap/gmap_z_str_any_test.go +++ b/container/gmap/gmap_z_unit_str_any_test.go @@ -7,6 +7,8 @@ package gmap_test import ( + "encoding/json" + "github.com/gogf/gf/frame/g" "testing" "github.com/gogf/gf/container/gmap" @@ -169,3 +171,47 @@ func Test_StrAnyMap_FilterEmpty(t *testing.T) { gtest.Assert(m.Size(), 1) gtest.Assert(m.Get("2"), 2) } + +func Test_StrAnyMap_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + data := g.MapStrAny{ + "k1": "v1", + "k2": "v2", + } + m1 := gmap.NewStrAnyMapFrom(data) + b1, err1 := json.Marshal(m1) + b2, err2 := json.Marshal(data) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + data := g.MapStrAny{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(data) + gtest.Assert(err, nil) + + m := gmap.NewStrAnyMap() + err = json.Unmarshal(b, m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) + gtest.Case(t, func() { + data := g.MapStrAny{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(data) + gtest.Assert(err, nil) + + var m gmap.StrAnyMap + err = json.Unmarshal(b, &m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) +} diff --git a/container/gmap/gmap_z_str_int_test.go b/container/gmap/gmap_z_unit_str_int_test.go similarity index 81% rename from container/gmap/gmap_z_str_int_test.go rename to container/gmap/gmap_z_unit_str_int_test.go index cf4e817f8..2cd1ae1dd 100644 --- a/container/gmap/gmap_z_str_int_test.go +++ b/container/gmap/gmap_z_unit_str_int_test.go @@ -7,6 +7,8 @@ package gmap_test import ( + "encoding/json" + "github.com/gogf/gf/frame/g" "testing" "github.com/gogf/gf/container/gmap" @@ -172,3 +174,47 @@ func Test_StrIntMap_FilterEmpty(t *testing.T) { gtest.Assert(m.Size(), 1) gtest.Assert(m.Get("2"), 2) } + +func Test_StrIntMap_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + data := g.MapStrInt{ + "k1": 1, + "k2": 2, + } + m1 := gmap.NewStrIntMapFrom(data) + b1, err1 := json.Marshal(m1) + b2, err2 := json.Marshal(data) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + data := g.MapStrInt{ + "k1": 1, + "k2": 2, + } + b, err := json.Marshal(data) + gtest.Assert(err, nil) + + m := gmap.NewStrIntMap() + err = json.Unmarshal(b, m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) + gtest.Case(t, func() { + data := g.MapStrInt{ + "k1": 1, + "k2": 2, + } + b, err := json.Marshal(data) + gtest.Assert(err, nil) + + var m gmap.StrIntMap + err = json.Unmarshal(b, &m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) +} diff --git a/container/gmap/gmap_z_str_str_test.go b/container/gmap/gmap_z_unit_str_str_test.go similarity index 81% rename from container/gmap/gmap_z_str_str_test.go rename to container/gmap/gmap_z_unit_str_str_test.go index 7f60e2940..3ff191d7d 100644 --- a/container/gmap/gmap_z_str_str_test.go +++ b/container/gmap/gmap_z_unit_str_str_test.go @@ -7,6 +7,8 @@ package gmap_test import ( + "encoding/json" + "github.com/gogf/gf/frame/g" "testing" "github.com/gogf/gf/container/gmap" @@ -169,3 +171,47 @@ func Test_StrStrMap_FilterEmpty(t *testing.T) { gtest.Assert(m.Size(), 1) gtest.Assert(m.Get("2"), "2") } + +func Test_StrStrMap_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + data := g.MapStrStr{ + "k1": "v1", + "k2": "v2", + } + m1 := gmap.NewStrStrMapFrom(data) + b1, err1 := json.Marshal(m1) + b2, err2 := json.Marshal(data) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + data := g.MapStrStr{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(data) + gtest.Assert(err, nil) + + m := gmap.NewStrStrMap() + err = json.Unmarshal(b, m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) + gtest.Case(t, func() { + data := g.MapStrStr{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(data) + gtest.Assert(err, nil) + + var m gmap.StrStrMap + err = json.Unmarshal(b, &m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) +} diff --git a/container/gmap/gmap_z_tree_map_test.go b/container/gmap/gmap_z_unit_tree_map_test.go similarity index 69% rename from container/gmap/gmap_z_tree_map_test.go rename to container/gmap/gmap_z_unit_tree_map_test.go index e04347dfc..9b70e1c2c 100644 --- a/container/gmap/gmap_z_tree_map_test.go +++ b/container/gmap/gmap_z_unit_tree_map_test.go @@ -7,6 +7,9 @@ package gmap_test import ( + "encoding/json" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/util/gconv" "testing" "github.com/gogf/gf/container/gmap" @@ -14,7 +17,7 @@ import ( "github.com/gogf/gf/util/gutil" ) -func Test_Tree_Map_Basic(t *testing.T) { +func Test_TreeMap_Basic(t *testing.T) { gtest.Case(t, func() { m := gmap.NewTreeMap(gutil.ComparatorString) m.Set("key1", "val1") @@ -48,7 +51,7 @@ func Test_Tree_Map_Basic(t *testing.T) { gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"}) }) } -func Test_Tree_Map_Set_Fun(t *testing.T) { +func Test_TreeMap_Set_Fun(t *testing.T) { m := gmap.NewTreeMap(gutil.ComparatorString) m.GetOrSetFunc("fun", getValue) m.GetOrSetFuncLock("funlock", getValue) @@ -59,14 +62,14 @@ func Test_Tree_Map_Set_Fun(t *testing.T) { gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false) } -func Test_Tree_Map_Batch(t *testing.T) { +func Test_TreeMap_Batch(t *testing.T) { m := gmap.NewTreeMap(gutil.ComparatorString) m.Sets(map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"}) gtest.Assert(m.Map(), map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"}) m.Removes([]interface{}{"key1", 1}) gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"}) } -func Test_Tree_Map_Iterator(t *testing.T) { +func Test_TreeMap_Iterator(t *testing.T) { expect := map[interface{}]interface{}{1: 1, "key1": "val1"} m := gmap.NewTreeMapFrom(gutil.ComparatorString, expect) @@ -89,7 +92,7 @@ func Test_Tree_Map_Iterator(t *testing.T) { gtest.Assert(j, 1) } -func Test_Tree_Map_Clone(t *testing.T) { +func Test_TreeMap_Clone(t *testing.T) { //clone 方法是深克隆 m := gmap.NewTreeMapFrom(gutil.ComparatorString, map[interface{}]interface{}{1: 1, "key1": "val1"}) m_clone := m.Clone() @@ -101,3 +104,47 @@ func Test_Tree_Map_Clone(t *testing.T) { //修改clone map,原 map 不影响 gtest.AssertIN("key1", m.Keys()) } + +func Test_TreeMap_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + data := g.MapAnyAny{ + "k1": "v1", + "k2": "v2", + } + m1 := gmap.NewTreeMapFrom(gutil.ComparatorString, data) + b1, err1 := json.Marshal(m1) + b2, err2 := json.Marshal(gconv.Map(data)) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + // Unmarshal + gtest.Case(t, func() { + data := g.MapAnyAny{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(gconv.Map(data)) + gtest.Assert(err, nil) + + m := gmap.NewTreeMap(gutil.ComparatorString) + err = json.Unmarshal(b, m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) + gtest.Case(t, func() { + data := g.MapAnyAny{ + "k1": "v1", + "k2": "v2", + } + b, err := json.Marshal(gconv.Map(data)) + gtest.Assert(err, nil) + + var m gmap.TreeMap + err = json.Unmarshal(b, &m) + gtest.Assert(err, nil) + gtest.Assert(m.Get("k1"), data["k1"]) + gtest.Assert(m.Get("k2"), data["k2"]) + }) +} diff --git a/container/gtree/gtree_redblacktree.go b/container/gtree/gtree_redblacktree.go index a7b9e6597..2bca67bb4 100644 --- a/container/gtree/gtree_redblacktree.go +++ b/container/gtree/gtree_redblacktree.go @@ -9,8 +9,8 @@ package gtree import ( "encoding/json" "fmt" - "github.com/gogf/gf/util/gconv" + "github.com/gogf/gf/util/gutil" "github.com/gogf/gf/container/gvar" "github.com/gogf/gf/internal/rwmutex" @@ -61,6 +61,26 @@ func NewRedBlackTreeFrom(comparator func(v1, v2 interface{}) int, data map[inter return tree } +// SetComparator sets/changes the comparator for sorting. +func (tree *RedBlackTree) SetComparator(comparator func(a, b interface{}) int) { + tree.mu.Lock() + defer tree.mu.Unlock() + tree.comparator = comparator + if tree.size > 0 { + data := make(map[interface{}]interface{}, tree.size) + tree.doIteratorAsc(tree.leftNode(), func(key, value interface{}) bool { + data[key] = value + return true + }) + // Resort the tree if comparator is changed. + tree.root = nil + tree.size = 0 + for k, v := range data { + tree.doSet(k, v) + } + } +} + // Clone returns a new tree with a copy of current tree. func (tree *RedBlackTree) Clone(safe ...bool) *RedBlackTree { newTree := NewRedBlackTree(tree.comparator, !tree.mu.IsSafe()) @@ -889,5 +909,23 @@ func (tree *RedBlackTree) nodeColor(node *RedBlackTreeNode) color { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (tree *RedBlackTree) MarshalJSON() ([]byte, error) { - return json.Marshal(tree.Map()) + return json.Marshal(gconv.Map(tree.Map())) +} + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (tree *RedBlackTree) UnmarshalJSON(b []byte) error { + if tree.mu == nil { + tree.mu = rwmutex.New() + tree.comparator = gutil.ComparatorString + } + tree.mu.Lock() + defer tree.mu.Unlock() + var data map[string]interface{} + if err := json.Unmarshal(b, &data); err != nil { + return err + } + for k, v := range data { + tree.doSet(k, v) + } + return nil } diff --git a/container/gvar/gvar.go b/container/gvar/gvar.go index 61522399b..7bcaf2d84 100644 --- a/container/gvar/gvar.go +++ b/container/gvar/gvar.go @@ -38,22 +38,6 @@ func New(value interface{}, safe ...bool) *Var { return v } -// MarshalJSON implements the interface MarshalJSON for json.Marshal. -func (v *Var) MarshalJSON() ([]byte, error) { - return json.Marshal(v.Val()) -} - -// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. -func (v *Var) UnmarshalJSON(b []byte) error { - var i interface{} - err := json.Unmarshal(b, &i) - if err != nil { - return err - } - v.Set(i) - return nil -} - // Set sets to , and returns the old value. func (v *Var) Set(value interface{}) (old interface{}) { if v.safe { @@ -338,3 +322,19 @@ func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) { return gconv.MapToMapsDeep(v.Val(), pointer, mapping...) } + +// MarshalJSON implements the interface MarshalJSON for json.Marshal. +func (v *Var) MarshalJSON() ([]byte, error) { + return json.Marshal(v.Val()) +} + +// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. +func (v *Var) UnmarshalJSON(b []byte) error { + var i interface{} + err := json.Unmarshal(b, &i) + if err != nil { + return err + } + v.Set(i) + return nil +} diff --git a/container/gvar/gvar_z_unit_test.go b/container/gvar/gvar_z_unit_test.go index 3271457c7..c44571f59 100644 --- a/container/gvar/gvar_z_unit_test.go +++ b/container/gvar/gvar_z_unit_test.go @@ -9,6 +9,8 @@ package gvar_test import ( "bytes" "encoding/binary" + "encoding/json" + "math" "testing" "time" @@ -300,12 +302,12 @@ func Test_Map(t *testing.T) { }) } -type StTest struct { - Test int -} - func Test_Struct(t *testing.T) { gtest.Case(t, func() { + type StTest struct { + Test int + } + Kv := make(map[string]int, 1) Kv["Test"] = 100 @@ -318,3 +320,47 @@ func Test_Struct(t *testing.T) { gtest.Assert(testObj.Test, Kv["Test"]) }) } + +func Test_Json(t *testing.T) { + // Marshal + gtest.Case(t, func() { + s := "i love gf" + v := gvar.New(s) + b1, err1 := json.Marshal(v) + b2, err2 := json.Marshal(s) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + + gtest.Case(t, func() { + s := math.MaxInt64 + v := gvar.New(s) + b1, err1 := json.Marshal(v) + b2, err2 := json.Marshal(s) + gtest.Assert(err1, err2) + gtest.Assert(b1, b2) + }) + + // Unmarshal + gtest.Case(t, func() { + s := "i love gf" + v := gvar.New(nil) + b, err := json.Marshal(s) + gtest.Assert(err, nil) + + err = json.Unmarshal(b, v) + gtest.Assert(err, nil) + gtest.Assert(v.String(), s) + }) + + gtest.Case(t, func() { + var v gvar.Var + s := "i love gf" + b, err := json.Marshal(s) + gtest.Assert(err, nil) + + err = json.Unmarshal(b, &v) + gtest.Assert(err, nil) + gtest.Assert(v.String(), s) + }) +}