• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-dotnet / 5716220196

31 Jul 2023 02:52PM UTC coverage: 82.478% (-0.3%) from 82.741%
5716220196

Pull #3261

github

aed2eb
fealebenpae
Merge remote-tracking branch 'origin/main' into yg/updated-marshaling

# Conflicts:
#	Realm/Realm/Handles/SharedRealmHandle.cs
Pull Request #3261: Use modern-er marshaling techniques

2029 of 2601 branches covered (78.01%)

Branch coverage included in aggregate %.

201 of 201 new or added lines in 21 files covered. (100.0%)

6246 of 7432 relevant lines covered (84.04%)

34048.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.32
/Realm/Realm/Native/Arena.cs
1
////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2023 Realm Inc.
4
//
5
// Licensed under the Apache License, Version 2.0 (the "License")
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16
//
17
////////////////////////////////////////////////////////////////////////////
18

19
using System;
20
using System.Collections.Generic;
21
using System.Diagnostics;
22
using System.Runtime.InteropServices;
23

24
namespace Realms.Native
25
{
26
    internal class Arena
27
        : IDisposable
28
    {
29
        private readonly Dictionary<int, List<Slab>> _slabs = new();
6,583✔
30
        private bool _disposed;
31

32
        public unsafe Buffer<T> Allocate<T>(int count = 1)
33
            where T : unmanaged
34
        {
35
            if (_disposed)
2,570,768!
36
            {
37
                throw new ObjectDisposedException(typeof(Arena).Name);
×
38
            }
39

40
            if (count < 1)
2,570,768!
41
            {
42
                throw new ArgumentOutOfRangeException(nameof(count));
×
43
            }
44

45
            if (!_slabs.TryGetValue(sizeof(T), out var bucket))
2,570,768✔
46
            {
47
                _slabs.Add(sizeof(T), bucket = new List<Slab>());
13,162✔
48
            }
49

50
            Slab? slab = null;
2,570,768✔
51
            foreach (var candidate in bucket)
27,006,589✔
52
            {
53
                if (candidate.Fits(count))
12,190,419✔
54
                {
55
                    slab = candidate;
2,515,785✔
56
                    break;
2,515,785✔
57
                }
58
            }
59

60
            if (slab == null)
2,570,768✔
61
            {
62
                bucket.Add(slab = new Slab(sizeof(T), count));
54,983✔
63
            }
64

65
            Debug.Assert(slab.ElementSize == sizeof(T), "Trying to append to slab with the wrong element size");
66

67
            return new Buffer<T>((T*)slab.Grab(count), count);
2,570,768✔
68
        }
69

70
        ~Arena()
71
        {
6,583✔
72
            Debug.Assert(_disposed, "BufferPool finalized without explicit disposal");
73
        }
13,166✔
74

75
        public void Dispose()
76
        {
77
            _disposed = true;
6,583✔
78

79
            foreach (var slabList in _slabs.Values)
39,490✔
80
            {
81
                slabList.ForEach(x => x.Dispose());
68,145✔
82
            }
83

84
            _slabs.Clear();
6,583✔
85
        }
6,583✔
86

87
        public readonly struct Buffer<T>
88
            where T : unmanaged
89
        {
90
            public unsafe T* Data { get; }
8,973,863✔
91

92
            public int Length { get; }
2,570,768✔
93

94
            internal unsafe Buffer(T* data, int length)
95
            {
96
                Data = data;
2,570,768✔
97
                Length = length;
2,570,768✔
98
            }
2,570,768✔
99
        }
100

101
        private class Slab : IDisposable
102
        {
103
            public IntPtr Buffer { get; }
2,625,751✔
104

105
            public int ElementSize { get; }
2,570,768✔
106

107
            public int MaxCount { get; }
14,816,170✔
108

109
            public int Count { get; private set; }
19,957,706✔
110

111
            public Slab(int elementSize, int minimumCount)
54,983✔
112
            {
113
                ElementSize = elementSize;
54,983✔
114
                Count = 0;
54,983✔
115

116
                var elementsPerPage = Environment.SystemPageSize / elementSize;
54,983✔
117
                MaxCount = (int)Math.Ceiling(minimumCount / (double)elementsPerPage) * elementsPerPage;
54,983✔
118

119
                Buffer = Marshal.AllocHGlobal(MaxCount * elementSize);
54,983✔
120
            }
54,983✔
121

122
            public bool Fits(int count) => Count + count <= MaxCount;
12,190,419✔
123

124
            public IntPtr Grab(int count)
125
            {
126
                if (count > MaxCount)
2,570,768!
127
                {
128
                    throw new InvalidOperationException($"Can't fit {count} items in a slab that can hold {MaxCount} items at most");
×
129
                }
130

131
                Debug.Assert(Fits(count), "Can't grab more from the slab than it can fit");
132

133
                var start = Buffer + (Count * ElementSize);
2,570,768✔
134
                Count += count;
2,570,768✔
135
                return start;
2,570,768✔
136
            }
137

138
            public void Dispose()
139
            {
140
                Marshal.FreeHGlobal(Buffer);
54,983✔
141
            }
54,983✔
142
        }
143
    }
144
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc