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