@@ -11,7 +11,7 @@ use crate::error::{DateError, UnknownEraError};
1111use crate :: provider:: { CalendarJapaneseModernV1 , EraStartDate } ;
1212use crate :: { types, AsCalendar , Date } ;
1313use icu_provider:: prelude:: * ;
14- use tinystr:: tinystr;
14+ use tinystr:: { tinystr, TinyAsciiStr } ;
1515
1616/// The [Japanese Calendar] (with modern eras only)
1717///
@@ -37,9 +37,49 @@ use tinystr::tinystr;
3737///
3838/// These eras are loaded from data, requiring a data provider capable of providing [`CalendarJapaneseModernV1`]
3939/// data.
40- #[ derive( Clone , Debug , Default ) ]
40+ #[ derive( Clone , Debug , Copy ) ]
4141pub struct Japanese {
42- eras : DataPayload < CalendarJapaneseModernV1 > ,
42+ last_era : PackedEra ,
43+ }
44+
45+ impl Default for Japanese {
46+ fn default ( ) -> Self {
47+ Self {
48+ last_era : PackedEra :: new ( REIWA ) ,
49+ }
50+ }
51+ }
52+
53+ #[ derive( Clone , Debug , Copy ) ]
54+ struct PackedEra {
55+ // The year is stored as an offset from `REIWA`,
56+ // which works until 2274
57+ year : u8 ,
58+ month : u8 ,
59+ day : u8 ,
60+ name : TinyAsciiStr < 8 > ,
61+ }
62+
63+ impl PackedEra {
64+ const fn new ( v : ( EraStartDate , TinyAsciiStr < 16 > ) ) -> Self {
65+ Self {
66+ year : ( v. 0 . year - REIWA . 0 . year ) as u8 ,
67+ month : v. 0 . month ,
68+ day : v. 0 . day ,
69+ name : v. 1 . resize ( ) ,
70+ }
71+ }
72+
73+ const fn expand ( self ) -> ( EraStartDate , TinyAsciiStr < 16 > ) {
74+ (
75+ EraStartDate {
76+ year : self . year as i32 + REIWA . 0 . year ,
77+ month : self . month ,
78+ day : self . day ,
79+ } ,
80+ self . name . resize ( ) ,
81+ )
82+ }
4383}
4484
4585impl Japanese {
@@ -50,11 +90,27 @@ impl Japanese {
5090 /// [📚 Help choosing a constructor](icu_provider::constructors)
5191 #[ cfg( feature = "compiled_data" ) ]
5292 pub const fn new ( ) -> Self {
53- Self {
54- eras : DataPayload :: from_static_ref (
55- crate :: provider:: Baked :: SINGLETON_CALENDAR_JAPANESE_MODERN_V1 ,
56- ) ,
57- }
93+ let last_era = const {
94+ if let Some ( & zerovec:: ule:: tuple:: Tuple2ULE ( start, name) ) =
95+ crate :: provider:: Baked :: SINGLETON_CALENDAR_JAPANESE_MODERN_V1
96+ . dates_to_eras
97+ . as_slice ( )
98+ . as_ule_slice ( )
99+ . last ( )
100+ {
101+ PackedEra :: new ( (
102+ EraStartDate {
103+ year : i32:: from_le_bytes ( start. year . 0 ) ,
104+ month : start. month ,
105+ day : start. day ,
106+ } ,
107+ name,
108+ ) )
109+ } else {
110+ panic ! ( "Invalid era data" )
111+ }
112+ } ;
113+ Self { last_era }
58114 }
59115
60116 icu_provider:: gen_buffer_data_constructors!( ( ) -> error: DataError ,
@@ -70,36 +126,59 @@ impl Japanese {
70126 provider : & D ,
71127 ) -> Result < Self , DataError > {
72128 Ok ( Self {
73- eras : provider. load ( Default :: default ( ) ) ?. payload ,
129+ last_era : PackedEra :: new (
130+ provider
131+ . load ( Default :: default ( ) ) ?
132+ . payload
133+ . get ( )
134+ . dates_to_eras
135+ . last ( )
136+ . ok_or_else ( || DataError :: custom ( "Invalid era data" ) ) ?,
137+ ) ,
74138 } )
75139 }
76140}
77141
78- const MEIJI_START : EraStartDate = EraStartDate {
79- year : 1868 ,
80- month : 10 ,
81- day : 23 ,
82- } ;
83- const TAISHO_START : EraStartDate = EraStartDate {
84- year : 1912 ,
85- month : 7 ,
86- day : 30 ,
87- } ;
88- const SHOWA_START : EraStartDate = EraStartDate {
89- year : 1926 ,
90- month : 12 ,
91- day : 25 ,
92- } ;
93- const HEISEI_START : EraStartDate = EraStartDate {
94- year : 1989 ,
95- month : 1 ,
96- day : 8 ,
97- } ;
98- const REIWA_START : EraStartDate = EraStartDate {
99- year : 2019 ,
100- month : 5 ,
101- day : 1 ,
102- } ;
142+ const MEIJI : ( EraStartDate , TinyAsciiStr < 16 > ) = (
143+ EraStartDate {
144+ year : 1868 ,
145+ month : 10 ,
146+ day : 23 ,
147+ } ,
148+ tinystr ! ( 16 , "meiji" ) ,
149+ ) ;
150+ const TAISHO : ( EraStartDate , TinyAsciiStr < 16 > ) = (
151+ EraStartDate {
152+ year : 1912 ,
153+ month : 7 ,
154+ day : 30 ,
155+ } ,
156+ tinystr ! ( 16 , "taisho" ) ,
157+ ) ;
158+ const SHOWA : ( EraStartDate , TinyAsciiStr < 16 > ) = (
159+ EraStartDate {
160+ year : 1926 ,
161+ month : 12 ,
162+ day : 25 ,
163+ } ,
164+ tinystr ! ( 16 , "showa" ) ,
165+ ) ;
166+ const HEISEI : ( EraStartDate , TinyAsciiStr < 16 > ) = (
167+ EraStartDate {
168+ year : 1989 ,
169+ month : 1 ,
170+ day : 8 ,
171+ } ,
172+ tinystr ! ( 16 , "heisei" ) ,
173+ ) ;
174+ const REIWA : ( EraStartDate , TinyAsciiStr < 16 > ) = (
175+ EraStartDate {
176+ year : 2019 ,
177+ month : 5 ,
178+ day : 1 ,
179+ } ,
180+ tinystr ! ( 16 , "reiwa" ) ,
181+ ) ;
103182
104183impl GregorianYears for & ' _ Japanese {
105184 fn extended_from_era_year (
@@ -110,82 +189,36 @@ impl GregorianYears for &'_ Japanese {
110189 if let Ok ( g) = CeBce . extended_from_era_year ( era, year) {
111190 return Ok ( g) ;
112191 }
113- let Some ( era) = era else {
114- // unreachable, handled by CeBce
115- return Err ( UnknownEraError ) ;
116- } ;
117-
118- // Avoid linear search by trying well known eras
119- if era == b"reiwa" {
120- return Ok ( year - 1 + REIWA_START . year ) ;
121- } else if era == b"heisei" {
122- return Ok ( year - 1 + HEISEI_START . year ) ;
123- } else if era == b"showa" {
124- return Ok ( year - 1 + SHOWA_START . year ) ;
125- } else if era == b"taisho" {
126- return Ok ( year - 1 + TAISHO_START . year ) ;
127- } else if era == b"meiji" {
128- return Ok ( year - 1 + MEIJI_START . year ) ;
129- }
130192
131- let era_start = self
132- . eras
133- . get ( )
134- . dates_to_eras
135- . iter ( )
136- . rev ( )
137- . find_map ( |( s, e) | ( e. as_bytes ( ) == era) . then_some ( s) )
193+ let ( start, _) = [ self . last_era . expand ( ) , REIWA , HEISEI , SHOWA , TAISHO , MEIJI ]
194+ . into_iter ( )
195+ . find ( |( _, name) | era == Some ( name. as_bytes ( ) ) )
138196 . ok_or ( UnknownEraError ) ?;
139- Ok ( era_start. year + year - 1 )
197+
198+ Ok ( year - 1 + start. year )
140199 }
141200
142201 fn era_year_from_extended ( & self , year : i32 , month : u8 , day : u8 ) -> types:: EraYear {
143202 let date: EraStartDate = EraStartDate { year, month, day } ;
144203
145- let ( start, era) = if date >= MEIJI_START
146- && self
147- . eras
148- . get ( )
149- . dates_to_eras
150- . last ( )
151- . is_some_and ( |( _, e) | e == tinystr ! ( 16 , "reiwa" ) )
204+ if let Some ( ( start, era) ) = [ self . last_era . expand ( ) , REIWA , HEISEI , SHOWA , TAISHO , MEIJI ]
205+ . into_iter ( )
206+ . find ( |& ( start, _) | date >= start)
152207 {
153- // We optimize for the five "modern" post-Meiji eras, which are stored in a smaller
154- // array and also hardcoded. The hardcoded version is not used if data indicates the
155- // presence of newer eras.
156- if date >= REIWA_START {
157- ( REIWA_START , tinystr ! ( 16 , "reiwa" ) )
158- } else if date >= HEISEI_START {
159- ( HEISEI_START , tinystr ! ( 16 , "heisei" ) )
160- } else if date >= SHOWA_START {
161- ( SHOWA_START , tinystr ! ( 16 , "showa" ) )
162- } else if date >= TAISHO_START {
163- ( TAISHO_START , tinystr ! ( 16 , "taisho" ) )
164- } else {
165- ( MEIJI_START , tinystr ! ( 16 , "meiji" ) )
208+ types:: EraYear {
209+ era,
210+ // TODO: return era indices?
211+ era_index : None ,
212+ year : year - start. year + 1 ,
213+ extended_year : year,
214+ ambiguity : types:: YearAmbiguity :: CenturyRequired ,
166215 }
167216 } else {
168- let data = & self . eras . get ( ) . dates_to_eras ;
169- #[ allow( clippy:: unwrap_used) ] // binary search
170- match data. binary_search_by ( |( d, _) | d. cmp ( & date) ) {
171- Err ( 0 ) => {
172- return types:: EraYear {
173- // TODO: return era indices?
174- era_index : None ,
175- ..CeBce . era_year_from_extended ( year, month, day)
176- } ;
177- }
178- Ok ( index) => data. get ( index) . unwrap ( ) ,
179- Err ( index) => data. get ( index - 1 ) . unwrap ( ) ,
217+ types:: EraYear {
218+ // TODO: return era indices?
219+ era_index : None ,
220+ ..CeBce . era_year_from_extended ( year, month, day)
180221 }
181- } ;
182-
183- types:: EraYear {
184- era,
185- era_index : None ,
186- year : year - start. year + 1 ,
187- extended_year : year,
188- ambiguity : types:: YearAmbiguity :: CenturyRequired ,
189222 }
190223 }
191224
0 commit comments