1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include <cstring>
34 
35 #include "mongo/base/data_type.h"
36 
37 namespace mongo {
38 
39 template <char C, typename T>
40 struct Terminated {
TerminatedTerminated41     Terminated() : value(DataType::defaultConstruct<T>()) {}
TerminatedTerminated42     Terminated(T value) : value(std::move(value)) {}
43     T value;
44 
TTerminated45     operator T() const {
46         return value;
47     }
48 };
49 
50 struct TerminatedHelper {
51     static Status makeLoadNoTerminalStatus(char c, size_t length, std::ptrdiff_t debug_offset);
52     static Status makeLoadShortReadStatus(char c,
53                                           size_t read,
54                                           size_t length,
55                                           std::ptrdiff_t debug_offset);
56     static Status makeStoreStatus(char c, size_t length, std::ptrdiff_t debug_offset);
57 };
58 
59 template <char C, typename T>
60 struct DataType::Handler<Terminated<C, T>> {
61     using TerminatedType = Terminated<C, T>;
62 
63     static Status load(TerminatedType* tt,
64                        const char* ptr,
65                        size_t length,
66                        size_t* advanced,
67                        std::ptrdiff_t debug_offset) {
68         size_t local_advanced = 0;
69 
70         const char* end = static_cast<const char*>(std::memchr(ptr, C, length));
71 
72         if (!end) {
73             return TerminatedHelper::makeLoadNoTerminalStatus(C, length, debug_offset);
74         }
75 
76         auto status = DataType::load(
77             tt ? &tt->value : nullptr, ptr, end - ptr, &local_advanced, debug_offset);
78 
79         if (!status.isOK()) {
80             return status;
81         }
82 
83         if (local_advanced != static_cast<size_t>(end - ptr)) {
84             return TerminatedHelper::makeLoadShortReadStatus(
85                 C, local_advanced, end - ptr, debug_offset);
86         }
87 
88         if (advanced) {
89             *advanced = local_advanced + 1;
90         }
91 
92         return Status::OK();
93     }
94 
95     static Status store(const TerminatedType& tt,
96                         char* ptr,
97                         size_t length,
98                         size_t* advanced,
99                         std::ptrdiff_t debug_offset) {
100         size_t local_advanced = 0;
101 
102         auto status = DataType::store(tt.value, ptr, length, &local_advanced, debug_offset);
103 
104         if (!status.isOK()) {
105             return status;
106         }
107 
108         if (length - local_advanced < 1) {
109             return TerminatedHelper::makeStoreStatus(C, length, debug_offset + local_advanced);
110         }
111 
112         if (ptr) {
113             ptr[local_advanced] = C;
114         }
115 
116         if (advanced) {
117             *advanced = local_advanced + 1;
118         }
119 
120         return Status::OK();
121     }
122 
123     static TerminatedType defaultConstruct() {
124         return TerminatedType();
125     }
126 };
127 
128 }  // namespace mongo
129