1 /* 2 * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 * 25 */ 26 package jdk.internal.foreign.layout; 27 28 import jdk.internal.foreign.Utils; 29 30 import java.lang.foreign.GroupLayout; 31 import java.lang.foreign.MemoryLayout; 32 import java.lang.foreign.SequenceLayout; 33 import java.lang.foreign.StructLayout; 34 import java.lang.foreign.UnionLayout; 35 import java.lang.foreign.ValueLayout; 36 import java.util.Objects; 37 import java.util.Optional; 38 39 public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & MemoryLayout> 40 permits AbstractGroupLayout, PaddingLayoutImpl, SequenceLayoutImpl, ValueLayouts.AbstractValueLayout { 41 42 private final long byteSize; 43 private final long byteAlignment; 44 private final Optional<String> name; 45 46 AbstractLayout(long byteSize, long byteAlignment, Optional<String> name) { 47 this.byteSize = MemoryLayoutUtil.requireByteSizeValid(byteSize, true); 48 this.byteAlignment = requirePowerOfTwoAndGreaterOrEqualToOne(byteAlignment); 49 this.name = Objects.requireNonNull(name); 50 } 51 52 public final L withName(String name) { 53 return dup(byteAlignment(), Optional.of(name)); 54 } 55 56 @SuppressWarnings("unchecked") 57 public final L withoutName() { 58 return name.isPresent() ? dup(byteAlignment(), Optional.empty()) : (L) this; 59 } 60 61 public final Optional<String> name() { 62 return name; 63 } 64 65 public L withByteAlignment(long byteAlignment) { 66 return dup(byteAlignment, name); 67 } 68 69 public final long byteAlignment() { 70 return byteAlignment; 71 } 72 73 public final long byteSize() { 74 return byteSize; 75 } 76 77 public boolean hasNaturalAlignment() { 78 return byteSize == byteAlignment; 79 } 80 81 // the following methods have to copy the same Javadoc as in MemoryLayout, or subclasses will just show 82 // the Object methods javadoc 83 84 /** 85 * {@return the hash code value for this layout} 86 */ 87 @Override 88 public int hashCode() { 89 return Objects.hash(name, byteSize, byteAlignment); 90 } 91 92 /** 93 * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified 94 * object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of 95 * the same kind, have the same size, name and alignment constraints. Furthermore, depending on the layout kind, additional 96 * conditions must be satisfied: 97 * <ul> 98 * <li>two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order}, 99 * and {@linkplain ValueLayout#carrier() carrier}</li> 100 * <li>two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and 101 * if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal</li> 102 * <li>two group layouts are considered equal if they are of the same type (see {@link StructLayout}, 103 * {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal</li> 104 * </ul> 105 * 106 * @param other the object to be compared for equality with this layout. 107 * @return {@code true} if the specified object is equal to this layout. 108 */ 109 @Override 110 public boolean equals(Object other) { 111 return other instanceof AbstractLayout<?> otherLayout && 112 name.equals(otherLayout.name) && 113 byteSize == otherLayout.byteSize && 114 byteAlignment == otherLayout.byteAlignment; 115 } 116 117 /** 118 * {@return the string representation of this layout} 119 */ 120 @Override 121 public abstract String toString(); 122 123 abstract L dup(long byteAlignment, Optional<String> name); 124 125 String decorateLayoutString(String s) { 126 if (name().isPresent()) { 127 s = String.format("%s(%s)", s, name().get()); 128 } 129 if (!hasNaturalAlignment()) { 130 s = byteAlignment() + "%" + s; 131 } 132 return s; 133 } 134 135 private static long requirePowerOfTwoAndGreaterOrEqualToOne(long value) { 136 if (!Utils.isPowerOfTwo(value) || // value must be a power of two 137 value < 1) { // value must be greater or equal to 1 138 throw new IllegalArgumentException("Invalid alignment: " + value); 139 } 140 return value; 141 } 142 143 }